How to solve this question using MO algorithm Codechef SMARKET

# | User | Rating |
---|---|---|

1 | tourist | 3496 |

2 | moejy0viiiiiv | 3288 |

3 | W4yneb0t | 3218 |

4 | TakanashiRikka | 3178 |

5 | Petr | 3173 |

6 | dotorya | 3117 |

7 | izrak | 3109 |

7 | Um_nik | 3109 |

9 | anta | 3106 |

10 | ershov.stanislav | 3105 |

# | User | Contrib. |
---|---|---|

1 | rng_58 | 174 |

2 | csacademy | 170 |

3 | Swistakk | 160 |

4 | tourist | 157 |

4 | Petr | 157 |

6 | Errichto | 154 |

7 | Zlobober | 147 |

8 | matthew99 | 142 |

9 | Endagorion | 141 |

10 | BledDest | 137 |

How to solve this question using MO algorithm Codechef SMARKET

↑

↓

Codeforces (c) Copyright 2010-2017 Mike Mirzayanov

The only programming contests Web 2.0 platform

Server time: Nov/23/2017 23:28:23 (c2).

Desktop version, switch to mobile version.

User lists

Name |
---|

I am not sure whether this will pass TL. Maintain the addition and deletion using BIT. Now for each query you need to find number of elements greater than k in our current window. This can be done using BIT. BIT adds an extra log(n) factor though.

You can get rid of the log(n) factor using a pretty standard trick. Suppose

cnt[K]is the number of blocks of lowest orderK. Maintain another arrayblock_cnt[SQRT_N]which stores the count of stable blocks corresponding to that range. So if you need to count the number of stable blocks >= x, you iterate overSQRT_Nblocks at most. Final asymptotic isO(N*sqrtN)which should fit in given time limit.Yeah.That passed for me with sqrt decomposition.That is when I realized segment tree is not the most complete data structure for query problems

Of course SQRT decomposition is stronger than segment tree, But you can solve this problem by persistent segment tree in O(nlgn) and also simple segment tree O(nlg^2n).

can you please explain how can we do that?

Predetermine all the stable blocks and sort them by order. Add all the blocks of order 1 to the persistent tree, then remove them again; add all the blocks of order 2 to the persistent tree, then remove then again; and so on.

Now you have a timepoint corresponding to blocks of order 1; a timepoint corresponding to blocks of order 2 and so on. When you process a query, you might end up with a block that is split up by

L_{i}, you might also end up with a block that is split up byR_{i}. There are also cases whereL_{i}andR_{i}belong to the same block. You can use a BST or similar method to consider these edge cases.You neither need a BIT nor the block_cnt[SQRT_N] method which satyaki3794 mentioned.

All you need is a simple cnt[N] array which you need to update every time the size of a stable block increases or decreases by 1.

Example. If the current stable block of lenght x increases in length by one, just do ++cnt[x+1] or if it decreases by one, do --cnt[x].

The reason this works is because the left/right pointer in MO's algo moves by one unit every step and hence the size of a stable block increases or decreases by 1 every step.

Therefore if we have a stable block of size 5, then it must have existed with size 1,2,3,4 at some point of time and hence the corresponding count array had been updated.

So finally, the number of blocks of order 'k' is simply cnt[k].

You can refer to my solution which used the above method here

Shit! This was awesome. Another easy way told to me by hm_98 is to divide each (L, R, k) into two queries (L, k) and (R, k). Sort them, then proceed left to right, use bit and query number of integers > k. Answer for one query would be query(R, k) — query(L, k).

I solved with persistent segment tree O(N * logN)

can you please explain it?

I am not familiar with a persistent segment tree so please point it out if what I describe resembles the idea of a persistent segment tree.

My solution uses binary search to find the answer. First I decomposed the problem into an equivalent problem. For every continuous range of identical numbers of size k, I replace that range with the numbers 1,2,...,k. For example, the array 20,10,10,7,7,7,10 becomes 1,1,2,1,2,3,1.

Now the query (l,r,k) becomes to find how many times the number 'k' occurs in the range (l,r). This would be equal to the query(1,r,k) — query(1,l-1,k). To find query (1,r,k) we can simply maintain vectors for each 'k' that store the index of each occurrence of 'k' in the array and binary search for number of such indices less than or equal to 'r'.

The only thing we need to be careful with is if we overcounted the left most instance of 'k' or undercounted the left most absence of 'k'. This can be easily checked by maintaining a pointer to the next '1' in the array. The overall complexity comes out to be O(Q*log(n)).

Here is a link to my submission : https://www.codechef.com/viewsolution/13229877