Dan4Life's blog

By Dan4Life, 5 weeks ago, In English

Hi Codeforces!

This is my first attempt at a tutorial blog XD.

Disclaimer: No headaches occured during the making of this blog

Problem statement

Given an integer array $$$A$$$ of length $$$n$$$ and $$$q$$$ of the following 5 types of queries:

  1. For all $$$i \in [l,r]$$$, change $$$A_i$$$ to $$$\max(A_i, v)$$$
  2. For all $$$i \in [l,r]$$$, change $$$A_i$$$ to $$$\min(A_i, v)$$$
  3. For all $$$i \in [l,r]$$$, change $$$A_i$$$ to $$$A_i + v$$$
  4. For all $$$i \in [l,r]$$$, change $$$A_i$$$ to $$$v$$$
  5. Output $$$A_i$$$
  • $$$ 1 \leq n,q \leq 10^6 $$$
  • $$$ 1 \leq l \leq r \leq n $$$
  • $$$ -10^9 \leq A_i, v \leq 10^9 $$$

The above is solvable with techniques like Segment Tree Beats in $$$\mathcal{O}(n+q\log^2{n})$$$, but as a binary search enthusiast, you didn't learn segment tree beats?

Don't worry, here's an easier, faster, and shorter solution that solves this particular problem in $$$\mathcal{O}(n+q\log{n})$$$

Prerequisites

You should know the following to solve the full problem:

  1. Basics of functions (including composite functions)
  2. Associative, commutative, and distributive properties of $$$\max$$$ / $$$\min$$$
  3. Basics of a lazy propagation segment tree (not required for some subproblems)

Assuming you know the above, let's begin! But first, I'll relax the constraints a bit...

Subproblem 1

These are the queries:

  1. For all $$$i \in \textbf{[1,n]}$$$, change $$$A_i$$$ to $$$\max(A_i, v)$$$
  2. For all $$$i \in \textbf{[1,n]}$$$, change $$$A_i$$$ to $$$\min(A_i, v)$$$

Print the final array $$$A$$$ $$$\newline$$$

Example input 1

We'll use the example input to try coming up with a solution to this problem.

Let $$$f_i(x)$$$ = output after applying only $$$i$$$th query to integer $$$x$$$

Let's define a composite function $$$F(x)$$$ = $$$f_Q(f_{Q-1}(\dots f_2(f_1(x))\dots))$$$

We basically want to output $$$F(x)$$$ for all $$$x \in A$$$

We can try plotting the graph of $$$F(x)$$$ against $$$x$$$ to hopefully find a pattern.

y = F(x)

Some observations about the above graph.

  • $$$F(x)$$$ is monotonically non-decreasing i.e. $$$F(x) \leq F(x+1)$$$
And why is that?
  • The graph can be divided into 3 sections depending on $$$x$$$:
$$$ \displaystyle y = F(x) = \begin{cases} 3 &\quad\text{for } x < 3 \\ x &\quad\text{for } 3 \leq x \leq 8 \\ 8 &\quad\text{for } 8 < x \\ \end{cases} $$$

In other words, $$$F(x) = \min(8,\max(x,3))$$$

In fact, it can be proven that $$$F(x) = \min(a,\max(x,b))$$$ for constants $$$a$$$, $$$b$$$ in the general case.

Mathy proof
Intuitive proof

From the mathy proof, we can repeatedly spam $$$f_{i+1}(f_i(x))$$$ till we get $$$F(x)$$$.

Our starting $$$ f_0(x) = \min( \infty , \max( x, -\infty ) ) $$$ as this does not affect $$$x$$$

Now, that we have calculated our $$$F(x)$$$ in $$$\mathcal{O}(Q)$$$ , we can use it to calculate our final array in $$$\mathcal{O}(1)$$$ per $$$x$$$.

Subproblem 1 Code (Mathy version)

From the intuitive proof, we can create this solution:

Subproblem 1 Code (Intuitive version)

Bonus: Solve this subproblem using $$$\max(a,\min(x,b))$$$ instead.

Ok, that was easy enough. Let's make it a bit harder.

Subproblem 2

These are the queries:

  1. For all $$$i \in [l,r]$$$, change $$$A_i$$$ to $$$\max(A_i, v)$$$
  2. For all $$$i \in [l,r]$$$, change $$$A_i$$$ to $$$\min(A_i, v)$$$
  3. Output $$$A_i$$$ $$$\newline$$$
Example input 2

In the first subproblem (mathy solution), we applied $$$f_i(x)$$$ to the entire array for each $$$i \in [1,q]$$$, but now we want to apply $$$f_i(x)$$$ only to $$$l_i, r_i$$$ for each $$$i \in [1,q]$$$. Doing this naively will take $$$\mathcal{O}(nq)$$$ time which is too slow.

We can speed this up with lazy segment trees instead. The idea is to only apply $$$f_i(x)$$$ to the $$$\mathcal{O}(\log n)$$$ segment tree nodes and lazily push down these functions from a segtree node to its children only when necessary (to make sure we apply the functions in the correct order).

Each node in the segment tree will contain the pair of integers $$$[a,b]$$$ which determines the function that is currently applied to that node (and eventually, all its decendants). Initially, each node's $$$[a,b]$$$ represents $$$f_0(x)$$$ and hence is equal to $$$[\infty,-\infty]$$$.

We apply to the $$$\mathcal{O}(\log n)$$$ nodes in the range $$$l_i, r_i$$$ for each query. Along the route to the target nodes, we push down the current node's $$$[a,b]$$$ to both children(if it's not $$$f_0(x)$$$) (to preserve order). $$$\newline$$$

Subproblem 2 Code

Bonus: Solve this subproblem using the intuitive solution instead.

Ok, now we're getting somewhere. It's still not hard enough though...

Subproblem 3

These are the queries:

  1. For all $$$i \in \textbf{[1,n]}$$$, change $$$A_i$$$ to $$$\max(A_i, v)$$$
  2. For all $$$i \in \textbf{[1,n]}$$$, change $$$A_i$$$ to $$$\min(A_i, v)$$$
  3. For all $$$i \in \textbf{[1,n]}$$$, change $$$A_i$$$ to $$$A_i + v$$$

Print the final array $$$A$$$ $$$\newline$$$

Example input 3

The example input3 is exactly the same as the example input1, but I added a couple of type 3 queries. We'll use example input3 to observe a pattern. On to plotting...

y = F(x)

It seems both graphs have the same structure. Let's compare both of them.

Graph with type 3 queries vs Same graph without type 3 queries

The new graph has the same 3-part structure as the old one, but with a horizontal translation by some $$$c$$$ for some new constants $$$a,b,c$$$

In other words:

$$$\displaystyle F(x) = \min(a,\max(b,x+c))$$$ for constants $$$a, b, c$$$ in the general case.

Proof is quite similar to the first subproblem.

Mathy proof
Intuitive proof

Our starting $$$ f_0(x) = \min( \infty , \max(-\infty, x+0) ) $$$ as this does not affect $$$x$$$

Subproblem 3 Code (Mathy version)

From the intuitive proof, we can create this solution:

Subproblem 3 Code (Intuitive version)

Bonus: We could also interpret the new graph as a vertical translation. Solve this subproblem using $$$\max(a,\min(x,b))+c$$$ instead.

Original problem

Armed with the ability to solve subproblems 1, 2, and 3, you should now be able to solve the original problem. Try solving it first : D

Full problem statement

How to solve? It's just subproblem 2+3 with an extra step

Handle range queries?
Handle Type 4 queries?
Final Code

Bonus: Solve this problem using the intuitive solution instead.

Final time complexity: $$$\mathcal{O}(n+q\log{n})$$$

Practice problems

I'll update this list if you find any more problems

  1. IOI 2014 Wall
  2. ABC 196 E Filters
  3. IOI 2021 Candies (Subtask 3)

Conclusion

Thanks to madlogic for proofreading this blog and useful suggestions!

If you found this trick useful, you might as well upvote :)

In the case of any bugs or questions, feel free to let me know.

Full text and comments »

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