### Nachia's blog

By Nachia, history, 8 months ago,

I got AC on Codeforces Round 905 (Div. 1) C. Minimum Array with my prewritten code sorting all arrays obtained (in lexicographic order) in $\mathcal{O}(n\log n + q\log q)$ time.

https://codeforces.com/contest/1887/submission/229244614

How is the processing time achieved? I made a tutorial (in Japanese) before. (https://www.mathenachia.blog/sortseqs/ and https://nachiavivias.github.io/cp-library/cpp/array/point-update-lex-sort.html) This time I make a brief explanation in English.

## Problem

First you are given an array $(A _ 0[0],A _ 0[1],\ldots ,A _ 0[N-1])$ of length $N$ . You will construct other $Q$ arrays $A _ 1, A _ 2, \ldots , A _ Q$ as follows :

• For $k=1,2,\ldots ,Q$ (in order) , you are given an integer $p _ k$ $( 0 \leq p _ k \leq N - 1 )$ and a value $x _ k$ . Overwrite $A _ k$ with the copy of $A _ {k-1}$ and change the value of $A _ {k}[p _ k]$ to $x _ k$ .

Find an array $(F _ 0,F _ 1,F _ 2,\ldots ,F _ Q)$ of nonnegative integers such that :

• $F _ i \lt F _ j \iff A _ i\lt A _ j$ (in lexicographic order) holds for $0 \leq i \leq Q$ , $0 \leq j \leq Q$ .
• Maximum value of $(F _ 0,F _ 1,F _ 2,\ldots ,F _ Q)$ is minimized.

In other words, sort all $Q+1$ arrays in lexicographic order.

## Algorithm

Above I wrote like $A _ a[b]$ , so I call $a$ as time index and $b$ as array index .

Divide and Conquer array index . After we could sort every half, we can get full answer in linear time with radix sort (sort by second digit, then stable sort by first digit) .

When we divide array index, changing points are also divided in two groups. So we can compress time index . We can bound the sum of number of time index as $\mathcal{O}(N+Q)$ in any layer of dividing. Of cource the number of the layers is $\mathcal{O}(\log N)$ . Therefore the entire process takes $\mathcal{O}((N+Q) \log (N+Q))$ time ( the term $Q\log Q$ is for sorting given values ).

## Main Usage

We can sometimes use this deterministic algorithm instead of randomized hash.

 » 8 months ago, # |   +25 You could also use (persistent) Merkel trees to solve this problem. And you can also avoid hashes: just set unique identifiers to nodes and keep a global hashmap that assigns a pair $(label_l, label_r)$ to the label of the root node. This approach, however, has a worse constant than what you’re describing, but at the same time feels like it could be applied in a little bit more general scenarios.
•  » » 8 months ago, # ^ |   +8 Let $(w_0, \ldots, w_{n-1})$ be a randomly generated sequence. By hash of a subsegment $[l, r]$ of array $a$ we will denote the value of $w_la_l + \ldots + w_ra_r$. If we build a persistent segment tree that stores the hashes, we can compare two versions of the array by finding the length of the minimal prefix with different hashes in these versions, then somehow compare the corresponding elements. However, I couldn't meet the memory limit with this approach