Proofs: Mo's algorithm
These are the human proofs of Mo's algorithm, at full length.
Mo's algorithm makes O(n sqrt q) moves full
This proof shows: complexity.
Let be the block size, the number of blocks, and let the queries be sorted by the key . Let be the queries in this order and . A round makes exactly calls of ADD and REMOVE, because each loop moves one end one step towards its target. So the total cost is
Lemma 1 (the right end). .
Proof. Group the rounds by the block ; at most groups are non-empty. Inside a group the are non-decreasing, so the moves inside the group add up to at most . The first round of each group moves by at most . Over at most groups the sum is at most .
Lemma 2 (the left end). .
Proof. If , both left ends lie in the same block of positions, so , and these rounds add up to less than . Otherwise (with for the start), and . The blocks increase along these rounds, so the sum of over them is at most , and there are at most such rounds. They add up to less than , because .
Theorem. With and , the algorithm makes calls of ADD and REMOVE, and with an cost per call it runs in time.
Proof. By Lemmas 1 and 2, . With , . With , because gives . So . Sorting the keys takes time, and the other lines of the loop take .
The bound of Lemma 1 is tight. For each block , take the two queries and . In sorted order, climbs to in each block and falls back to at the start of the next one, so , which is about .
Mo's algorithm returns the value of each query range full
This proof shows: correctness, termination.
Let be the array and the queries, with and . Write for the multiset . The holes satisfy the contract: if is the state of , then ADD makes it the state of for , ADD makes it the state of for , REMOVE makes it the state of for , REMOVE makes it the state of for , and ANSWER returns .
Invariant (I). Before each round of line L3 and after each step of lines L4 to L7, and is the state of .
Lemma 1. (I) holds before the first round.
Proof. Line L2 sets and the state of the empty window, which is .
Lemma 2. If (I) holds at the start of a round for the query , then it holds after each step of lines L4 to L7, every call of ADD and REMOVE meets the contract, and at the end and .
Proof. Let be the window at the start.
Line L4 runs while . Each step has because , sets and calls ADD on the new , which is the item that enters on the left. stays at most because it decreases. The loop stops with .
Line L5 runs while . Each step has , calls ADD, the item that enters on the right, and sets . The loop stops with .
Now and . Line L6 runs while . During this loop , so and REMOVE meets the contract; then . The loop stops with .
Line L7 runs while . During this loop , so , the step sets and REMOVE removes , the last item of the old window, and afterwards. The loop stops with .
Each step keeps (I) by the contract of the hole it calls.
Theorem 1 (correctness). For each , .
Proof. Line L1 lists every index exactly once, because it sorts a permutation. By Lemma 1 and Lemma 2, by induction over the rounds, (I) holds at line L8 of the round of with . So ANSWER returns , and line L8 stores it at index . Later rounds write only other indices.
Theorem 2 (termination). The algorithm stops after a finite number of calls of ADD and REMOVE.
Proof. Each of the four loops of a round changes one end by one step towards a fixed target and stops when the target is reached, so a round makes at most calls. There are rounds.
Remark (the order of the loops). The proof of Lemma 2 uses that lines L4 and L5 run before lines L6 and L7. If the left end shrinks first, for example from to the query , then passes , and REMOVE is called on items that are not in the window, which breaks the contract.