I have been thinking about the following problem lately: we are given a tree (rooted at vertex 1) and an array. We want to answer some queries. In each query, we are given a vertex v and two indices L and R, and we want to output the "YES" or "NO". The answer is "YES" if on the subarray from L to R, there exists a vertex u such that v belongs to the subtree of u.
I could think of a solution with quadratic time complexity (loop from L to R and check if u exists), which is not efficient.
Another thought I had was to maintain two arrays tin and tout, which store the time when we process the vertex and when we finish processing the vertex. Then, we just need to check if there exists u on the subsegment such that tin[u] <= tin[v] and tout[u] >= tout[v], but I haven't thought of how to get solution from this.
Do you have idea how to solve this? Thanks!
You can answer all the queries offline in $$$O(n + q + m \log m)$$$ ($$$m$$$ is the length of the array).
tin
.lower_bound
.Online $$$O((n + q + m) \log^2{n})$$$ solution:
The key idea is the same as TheScrasse's solution: We query on ancestors and check if some ancestor lies within given range, instead of querying on the range in the original array and checking if some ancestor lies in that range.
Firstly, let us solve the following subproblem: Given an array $$$a$$$ of length $$$n$$$, answer queries "does there lie some element having value in range $$$[L, R]$$$ in prefix of length $$$x$$$?"
The first thought that comes to your mind is probably merge sort tree, which can answer these queries in $$$O(\log^2{n})$$$, but we can do better than this by exploiting the fact that all the queried ranges of indices are prefixes of the form $$$[1, x]$$$.
So, let us build another array $$$b$$$, such that $$$b$$$ contains each number from $$$1$$$ to $$$n$$$ once, and $$$a_{b_i} \leq a_{b_{i + 1}}$$$ (ie. sort $$$a$$$ by $$$a_i$$$ and store original index at each position instead of storing the value $$$a_i$$$). Now build a segment tree upon this array $$$b$$$, and now each query $$$(L, R, x)$$$ can be answered in the following way:
So we have learnt how to solve this subproblem in $$$O(\log{n})$$$ time per query.
Now let's think about how we can solve the original problem using hld. For each heavy path we will build the above described segment tree (the array $$$a$$$ is basically the indices in original array for nodes in the path, ordered by depth).
How to answer some query $$$(L, R, v)$$$?
The path $$$[root, v]$$$ gets divided into $$$O(\log{n})$$$ heavy and light paths.
Therefore, each query is answered in $$$O(\log{n} + \log^2{n})$$$ time, and taking precomputation into account, we achieve a total time complexity of $$$O((n + q + m) \log^2{n})$$$.