Worst-Performing Ads by CTR in a Campaign Tree
Problem statement
An ad platform keeps its ads in a tree. A campaign is a root. A campaign can hold ad groups and ads, and an ad group can hold ads. Process a list of operations in order:
["ADD", nodeId, parentId, type]registers a campaign, ad group or ad underparentId. A campaign has no parent, so itsparentIdis the empty string.["EVENT", adId, date, eventType]records oneCLICKor oneIMPRESSIONfor the ad on that date.["WORST", nodeId, date, k]returns thekworst-performing ads under the campaign or ad groupnodeIdon that date.
An ad is under a node if the node is its parent or its parent's parent. For a WORST query, use only the events recorded before it. An ad's click-through rate (CTR) on a date is its clicks on that date divided by its impressions on that date. Only ads under the node with at least one impression on that date are ranked. Rank them by CTR, lowest first. If two ads have the same CTR, the one with more impressions comes first; if they also have the same number of impressions, the smaller ID (in lexicographic order) comes first. Clicks are not limited by impressions, so a CTR can be above 1. Dates are labels: two events are on the same date only when their date strings are equal.
For each WORST operation, in order, return one string: the IDs of the first k ranked ads, worst first, joined with commas. If fewer than k ads are ranked, list all of them. If none are ranked, return the empty string.
Function
runAdOperations(operations: String[][]) → String[]Examples
Example 1
operations = [["ADD","c1","","CAMPAIGN"],["ADD","g1","c1","AD_GROUP"],["ADD","a1","c1","AD"],["ADD","a2","g1","AD"],["ADD","a3","g1","AD"],["EVENT","a1","2026-11-05","IMPRESSION"],["EVENT","a1","2026-11-05","IMPRESSION"],["EVENT","a1","2026-11-05","IMPRESSION"],["EVENT","a1","2026-11-05","IMPRESSION"],["EVENT","a1","2026-11-05","CLICK"],["EVENT","a2","2026-11-05","IMPRESSION"],["EVENT","a2","2026-11-05","IMPRESSION"],["EVENT","a3","2026-11-05","IMPRESSION"],["EVENT","a3","2026-11-05","IMPRESSION"],["EVENT","a3","2026-11-05","IMPRESSION"],["EVENT","a3","2026-11-05","IMPRESSION"],["EVENT","a3","2026-11-05","CLICK"],["EVENT","a3","2026-11-05","CLICK"],["WORST","c1","2026-11-05","2"],["WORST","g1","2026-11-05","5"]]return = ["a2,a1","a2,a3"]Campaign c1 holds ad a1 directly and ads a2 and a3 through ad group g1. On 2026-11-05 the CTRs are: a1 1/4 = 0.25, a2 0/2 = 0, a3 2/4 = 0.5. The 2 worst ads under c1 are a2 then a1. Ad group g1 holds only a2 and a3, so asking for 5 returns just those two, worst first.
Example 2
operations = [["ADD","c2","","CAMPAIGN"],["ADD","b1","c2","AD"],["ADD","b2","c2","AD"],["ADD","b3","c2","AD"],["EVENT","b1","2026-01-01","IMPRESSION"],["EVENT","b1","2026-01-01","IMPRESSION"],["EVENT","b1","2026-01-01","CLICK"],["EVENT","b2","2026-01-01","IMPRESSION"],["EVENT","b2","2026-01-01","IMPRESSION"],["EVENT","b2","2026-01-01","IMPRESSION"],["EVENT","b2","2026-01-01","IMPRESSION"],["EVENT","b2","2026-01-01","CLICK"],["EVENT","b2","2026-01-01","CLICK"],["EVENT","b3","2026-01-01","CLICK"],["EVENT","b3","2026-01-02","IMPRESSION"],["WORST","c2","2026-01-01","3"],["WORST","c2","2026-01-03","1"]]return = ["b2,b1",""]On 2026-01-01, b1 has CTR 1/2 and b2 has CTR 2/4, the same 0.5. They tie, so the ad with more impressions, b2, comes first. b3 has a click but no impression on 2026-01-01 (its only impression is on 2026-01-02), so it is not ranked. No ad has an impression on 2026-01-03, so that query returns an empty string.
Constraints
2 <= operations.length <= 5000- Each operation has exactly 4 strings:
["ADD", nodeId, parentId, type],["EVENT", adId, date, eventType]or["WORST", nodeId, date, k]. - Every ID is 1 to 10 lowercase English letters or digits, and no two nodes share an ID.
typeisCAMPAIGN,AD_GROUPorAD. A campaign'sparentIdis the empty string, an ad group's parent is a campaign, and an ad's parent is a campaign or an ad group. Every parent is added before its children.- In an
EVENToperation,adIdis an ad added earlier andeventTypeisCLICKorIMPRESSION. - Every
datehas the formYYYY-MM-DD. - In a
WORSToperation,nodeIdis a campaign or an ad group added earlier, andkis a decimal integer with1 <= k <= 5000. - There is at least one
WORSToperation.