Many questions in competitive programming are based on update and find queries.
For e.g. given an array of N elements and Q queries. Each query has L and R and you need to print the minimum array element from a[L] to a[R]. N = 10^5, Q = 10^5, 1 <= L <= R <= N. If you do it naïve it way, it would take O(N*Q) which would give TLE.
Basically, there are two types of approaches for solving such type of questions.
You just print the answer for each query instantaneously in the order they appear in input.
You input and store all queries, sort them according to some comparison function, solve all in sorted order, output answer for all queries in order they appear in input.
- PreOrder Array:
Create another array pre , where pre[i] stores information about [0,i]
For eg, you need range sum from L to R in each query quickly.
Solution: Create preorder array, where pre[i] = sum from 0 to i = pre[i-1] + a[i]
So, for each query, answer = pre[R] – pre[L-1].
But this is a static structure and it doesn’t work when you need to update array elements.
- Segment Tree: This is the most useful data structure for this type of questions.
Segment Tree with lazy propagation: (For range update queries)
- Binary Indexed Tree/Fenwick tree :
- Square Root Decomposition :
- Disjoint Set Union :
- Reverse Process Queries:
Process queries in from last to first. For example, if query is to delete something, solving queries in reverse order, it becomes insert instead of delete. This approach helps when inverse operation is easier to process then normal query operation.
https://www.codechef.com/MARCH15/problems/MTRWY (Do read editorial for it.)
- Sorting queries based on their ‘R’. R = right end of range query (L,R)
- Mo’s Algorithm: