re-wa-tl-ok's blog

By re-wa-tl-ok, history, 14 months ago, translation, In English
Problem 1:
Problem 2:

Of course, offline, both tasks can be solved using Mo algorithm and 3DMo (there are many ways like scanline, etc.), but there are some problems where we need to answer queries online. The solution with a persistent segment tree, i heard from Andrew-13, is good, but it does not support update queries. So, let's get started and learn how to solve both problems.

Problem 1: $$$O(log(n)^2)$$$ on query using 2D Implicit Segment Tree

What is a "unique" element in a subarray? — an element in a subarray $$$a[ l, r ]$$$ is considered unique if it appears exactly once in that range => it's previous occurrence (if any) is before $$$l$$$ and it's next occurrence (if any) is after $$$r$$$.

Let's introduce the definition: link of $$$a_i$$$ is a reference that points to an equal element that is located closer to the left/right than others. If there are no such links, the left link leads to $$$-1$$$, and the right link leads to $$$n$$$.

Now we need to find the number of elements on $$$[ l, r ]$$$ such that their left links point to elements at positions < $$$l$$$, and the right links to elements at positions > $$$r$$$. So, let's build $$$future$$$ and $$$last$$$ — arrays containing links to the closest equal elements:

  1. $$$future_i$$$ contains the index of the closest element equal to $$$a_i$$$ on the right (or $$$n$$$ if there are no such elements).
  2. $$$last_i$$$ contains the index of the closest element equal to $$$a_i$$$ on the left (or $$$-1$$$ if there are no such elements).

We will consider current query: $$$[ l, r ]$$$. Let's just count elements with $$$future_i$$$ > $$$r$$$ and $$$last_i$$$ < $$$l$$$ => — $$$last_i$$$ > — $$$l$$$ => $$$1000000$$$ — $$$last_i$$$ > $$$1000000$$$ — $$$l$$$. Now all coordinates are positive, because $$$l$$$, $$$last_i$$$ < $$$n$$$ < $$$10^5$$$.

So, we need to count the number of points ($$$x_i$$$, $$$y_i$$$) = ($$$1000000$$$ — $$$last_i$$$, $$$future_i$$$) which lie in the upper right part of plane relative to ($$$minX$$$, $$$minY$$$) = ($$$1000000$$$ — $$$l$$$, $$$r$$$). 2D Implicit Segment Tree can easily solve this problem in $$$O(log(n)^2)$$$.

This would be a solution if there were no points:

  1. lies before the left border and the right link crosses the right border.
  2. lies after the right border and the left link crosses the left border.

So, we get the number of unnecessary points and subtract it from the total answer. This can be realized with simple Segment Tree with Treaps in nodes, because we actually need to be able to answer to 2 queries:

  1. count the number of elements on [ $$$0$$$, $$$l$$$ — $$$1$$$ ] that have right links > $$$r$$$.
  2. count the number of elements on [ $$$r$$$ + $$$1$$$, $$$n$$$ — $$$1$$$ ] that have left links < $$$l$$$.

Finally: Precalc ~ $$$O(n * log(n)^2)$$$; Answer to query ~ $$$O(log(n)^2)$$$.

Code
Problem 2: $$$O(log(n)^2)$$$ on query using 2D Implicit Segment Tree

What about update queries? Note that we can also easily answer them in $$$O(log(n)^2)$$$. Let's call $$$L$$$ — the maximum position in $$$a$$$ that < $$$i$$$ and $$$a_L$$$ = $$$X$$$; $$$F$$$ — the minimum position in $$$a$$$ that > $$$i$$$ and $$$a_F$$$ = $$$X$$$, where $$$X$$$ is the element in the update query. If there are no such elements, just put: $$$L$$$ = $$$-1$$$; $$$F$$$ = $$$n$$$.

When updating an element $$$a_i$$$, the links only change:

  1. $$$a[i]$$$ links.
  2. $$$a[last_i]$$$ links.
  3. $$$a[future_i]$$$ links.
  4. $$$a[L]$$$ links.
  5. $$$a[F]$$$ links.

It remains to remember to update Segment Tree of Treaps and the points on the 2D Segment Tree plane.

Finally: Precalc ~ $$$O(n * log(n)^2)$$$; Answer to query ~ $$$O(log(n)^2)$$$.

Code

You can find my solution here.

  • Vote: I like it
  • +71
  • Vote: I do not like it

| Write comment?
»
14 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Auto comment: topic has been updated by re-wa-tl-ok (previous revision, new revision, compare).

»
14 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Auto comment: topic has been updated by M1chael_Petrov (previous revision, new revision, compare).

»
14 months ago, hide # |
 
Vote: I like it +24 Vote: I do not like it

this problem is exactly identical to 2D point update, 2D range sum query, as the transformation gives. In the first case, no point update necessary.

There are three optoins for the first case, wavelet tree, merge sort tree, or persistent segment tree. All of which are n log n, but wavelet tree allow bit-compression so it is actually n log n / 64 in memory, n log n time, which is the best solutoin.

The second case is a general unavoidable full on 2D queries, costing n log^2 n. but you can still choose between 2D BIT (if range small), red-black tree on segment tree, and 2d segment tree. If all queries are given ahead of time (offline) you can change the red-black tree on segment tree into BIT on segment tree after coordinate compression, which would be clearley the best option. If one of the range is dense (which is applicable here), use red-black tree on segment tree.

I think the solution to this problem is best presented by clearly splitting to a "reduction" component and an "data structure" component, I hope the examples I give show you why such a split is desirable.

»
13 months ago, hide # |
Rev. 2  
Vote: I like it +3 Vote: I do not like it

There's yet another way: use sqrt decomposition online. $$$O(n\sqrt{n}\log(n))$$$. My idea is that when an element changes, you should change the left link too. Then use a similar idea as a merge sort tree, i.e. maintain a sorted list of elements in each block. It runs quite fast and beats all MO 3D implementations that I know. The problem (in Vietnamese): https://lqdoj.edu.vn/problem/diffquery2, my solution: https://gist.github.com/pt13762104/7a29af08b17fbffb87ca35e0ffcc0e88. Also I don't think you need the right link when you already have the left link.

  • »
    »
    13 months ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    Your nickname is very suitable for this way of solving the problem) Yes, I submitted a similar solution last year.

    "Also I don't think you need the right link when you already have the left link." — It depends on what problem you're solving. To find the number of different elements, it is enough to store one link; and to find unique, you need 2, because both will have to go out of range. ([1, 2, 3, 3] has 2 unique elements: 1 and 2). Both tasks have their pros and cons in implementation.

    As I understand it, here you are talking about different elements. Perhaps I really should have defined the "unique elements" at the beginning of the blog. Then there would be no misunderstandings.

»
13 months ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

I think this is a clearer solution.

»
13 months ago, hide # |
Rev. 2  
Vote: I like it 0 Vote: I do not like it

We can still use Mo's algorithm for online queries. Maybe you think this is unbelievable, but this is really possible.

See this tutorial (In Chinese, but you can copy Markdown src here and do AI translation). The provided code is for problem P1903, which is almost the same as Problem 2 at the start of this blog