Algorithm Search⌘K

Proofs: Implicit treap

These are the human proofs of Implicit treap, at full length.

Split and merge on positions keep the represented sequence full

This proof shows: correctness.

Write s⋅s′s \cdot s' for the concatenation of sequences, s‾\overline{s} for the reverse of ss, and ∣s∣|s| for the length. The sequence that a subtree tt represents is defined, with the lazy flag, by

seq(nil)=⟨⟩,seq(t)={seq(t.left)⋅⟨t.value⟩⋅seq(t.right)if t.rev=false,seq(t.left)⋅⟨t.value⟩⋅seq(t.right)‾if t.rev=true.\text{seq}(\text{nil}) = \langle\rangle, \qquad \text{seq}(t) = \begin{cases} \text{seq}(t.left) \cdot \langle t.value \rangle \cdot \text{seq}(t.right) & \text{if } t.rev = \text{false},\\ \overline{\text{seq}(t.left) \cdot \langle t.value \rangle \cdot \text{seq}(t.right)} & \text{if } t.rev = \text{true}. \end{cases}

So toggling the flag of tt replaces seq(t)\text{seq}(t) by its reverse, because s‾‾=s\overline{\overline{s}} = s. A subtree is valid when:

  1. (H) each node has a priority at least as large as the priorities of its children;
  2. (S) each node tt has t.size=∣seq(t)∣t.size = |\text{seq}(t)| and t.totalt.total equal to the sum of the items of seq(t)\text{seq}(t).

Reversal does not change the length or the sum of a sequence, so (S) can be checked without regard to the flags: ∣seq(t)∣=∣seq(t.left)∣+1+∣seq(t.right)∣|\text{seq}(t)| = |\text{seq}(t.left)| + 1 + |\text{seq}(t.right)| in both cases, and the same for the sum. That is what UPDATE computes.

Lemma 1 (PUSH). If tt is valid, then after PUSH(t)(t) the subtree is valid, seq(t)\text{seq}(t) is the same, and t.revt.rev is false.

Proof. If t.revt.rev is false, nothing changes. Otherwise let ll, rr be the children and vv the value. Before, seq(t)=seq(l)⋅⟨v⟩⋅seq(r)‾=seq(r)‾⋅⟨v⟩⋅seq(l)‾\text{seq}(t) = \overline{\text{seq}(l) \cdot \langle v \rangle \cdot \text{seq}(r)} = \overline{\text{seq}(r)} \cdot \langle v \rangle \cdot \overline{\text{seq}(l)}. PUSH makes rr the left child and ll the right child, toggles both of their flags, which makes their sequences seq(r)‾\overline{\text{seq}(r)} and seq(l)‾\overline{\text{seq}(l)}, and clears t.revt.rev. So the new seq(t)\text{seq}(t) is the same. Each node has the same children as a set, so (H) holds, and no length or sum changes, so (S) holds. □\square

Lemma 2 (SPLIT). Let tt be valid and i≥0i \ge 0. SPLIT(t,i)(t, i) returns valid subtrees AA and BB, made of the nodes of tt, with seq(A)\text{seq}(A) the first min⁡(i,∣seq(t)∣)\min(i, |\text{seq}(t)|) items of seq(t)\text{seq}(t) and seq(B)\text{seq}(B) the rest.

Proof. By induction on the size of tt. If tt is nil, line L1 returns two empty trees. Otherwise, by Lemma 1, after line L2, seq(t)=seq(l)⋅⟨v⟩⋅seq(r)\text{seq}(t) = \text{seq}(l) \cdot \langle v \rangle \cdot \text{seq}(r) with ll, rr the children, and t.revt.rev is false. Let s=∣seq(l)∣=size(l)s = |\text{seq}(l)| = size(l).

If s<is < i (line L3), the first ii items are all of seq(l)\text{seq}(l), then vv, then the first i−s−1i - s - 1 items of seq(r)\text{seq}(r). By the induction hypothesis the call on rr returns A′A' with those i−s−1i - s - 1 items and B′B' with the rest. Setting t.right=A′t.right = A' gives seq(t)=seq(l)⋅⟨v⟩⋅seq(A′)\text{seq}(t) = \text{seq}(l) \cdot \langle v \rangle \cdot \text{seq}(A'), which is the first part, and B′B' is the rest. The nodes of A′A' come from rr, so their priorities are at most that of tt, and (H) holds at tt; UPDATE makes (S) hold at tt.

If i≤si \le s (line L4), the first ii items all lie in seq(l)\text{seq}(l), and the case is the mirror image, with t.left=B′t.left = B'. □\square

Lemma 3 (MERGE). Let aa and bb be valid, with disjoint nodes. MERGE(a,b)(a, b) returns a valid subtree, made of the nodes of aa and bb, with sequence seq(a)⋅seq(b)\text{seq}(a) \cdot \text{seq}(b).

Proof. By induction on the total size. If one of them is nil, line L5 returns the other. Let a.prio>b.prioa.prio > b.prio (line L6). After PUSH(a)(a), seq(a)=seq(a.left)⋅⟨a.value⟩⋅seq(a.right)\text{seq}(a) = \text{seq}(a.left) \cdot \langle a.value \rangle \cdot \text{seq}(a.right). By the induction hypothesis, MERGE(a.right,b)(a.right, b) is valid with sequence seq(a.right)⋅seq(b)\text{seq}(a.right) \cdot \text{seq}(b), so the new seq(a)\text{seq}(a) is seq(a)⋅seq(b)\text{seq}(a) \cdot \text{seq}(b) for the old aa. The root of the merged subtree is a node of a.righta.right or of bb. The first have priority at most a.prioa.prio by (H) in aa, and the second at most b.prio<a.priob.prio < a.prio by (H) in bb. So (H) holds at aa, and UPDATE gives (S). The case a.prio≤b.prioa.prio \le b.prio (line L7) is the mirror image, with bb as the root. □\square

The operations. Let the whole tree be valid and represent the list LL.

  • INSERT(i,x)(i, x) (line L8): by Lemma 2 the split gives L[0..i)L[0..i) and L[i..n)L[i..n), and a new node is a valid tree for ⟨x⟩\langle x \rangle. By Lemma 3 the two merges give L[0..i)⋅⟨x⟩⋅L[i..n)L[0..i) \cdot \langle x \rangle \cdot L[i..n).
  • DELETE(i)(i) (line L9): the two splits give L[0..i)L[0..i), the one-node tree MM for ⟨L[i]⟩\langle L[i] \rangle and L[i+1..n)L[i+1..n). The merge gives the list without L[i]L[i], and the value of MM is returned.
  • REVERSE(lo,hi)(lo, hi) (lines L10 and L11): the splits give L[0..lo)L[0..lo), MM for L[lo..hi)L[lo..hi) and L[hi..n)L[hi..n). Toggling the flag of MM makes seq(M)\text{seq}(M) the reverse of L[lo..hi)L[lo..hi); it changes no priority, length or sum, so MM stays valid. The merges give the list with that range reversed.
  • RANGE-SUM(lo,hi)(lo, hi) (line L12): the same splits give MM for L[lo..hi)L[lo..hi), and by (S) its total is the sum asked for. Merging back restores the tree for LL.
  • GET(i)(i): at each node, after PUSH, seq(t)=seq(l)⋅⟨v⟩⋅seq(r)\text{seq}(t) = \text{seq}(l) \cdot \langle v \rangle \cdot \text{seq}(r), so the item of index ii is in ll when i<size(l)i < size(l), is vv when i=size(l)i = size(l), and is item i−size(l)−1i - size(l) - 1 of seq(r)\text{seq}(r) otherwise.

Theorem. Starting from the empty list, after any sequence of operations the tree is valid, represents the list that the same operations give on a plain array, and every query returns the right answer.

Proof. The empty tree is valid and represents the empty list, and each operation keeps this by the cases above. ■\blacksquare

Back to Implicit treap