Proofs: Link-cut tree
These are the human proofs of Link-cut tree, at full length.
The operations of a link-cut tree keep the preferred path invariant full
This proof shows: correctness.
We use invariant (L) of the page. Each real tree is rooted. For a splay tree , write for its symmetric order with all pending reversal bits applied: a bit on a vertex reverses the sequence of its whole subtree. (L1) says that is a vertical path of the real tree, with a child of . (L2) says that the parent pointer of the splay root of is the real parent of , or nothing if is the root of its real tree. (L3) says that each stored sum and maximum is that of the values in the splay subtree. Each vertex lies in exactly one splay tree.
Lemma 1 (splaying). Pushing a reversal bit and rotating inside a splay tree change neither nor the set of its vertices, and they keep (L3). After SPLAY, is the splay root and its parent pointer is the old path-parent of .
Proof. Pushing the bit of swaps the children of and toggles the bits of both children. The sequence of the subtree of was the reverse of , with the children's sequences read with their own bits; after the push it is , which is the same sequence. SPLAY pushes the bits on the path from the splay root to before any rotation, so every rotation acts on vertices without pending bits, where it keeps the symmetric order as in any binary search tree. Each rotation recomputes the aggregates of the two rotated vertices from their new children, which keeps (L3). In a rotation at the splay root , the new splay root takes the parent pointer of , so the path-parent is kept.
Lemma 2 (access). After ACCESS, (L) holds, the splay tree of holds exactly the path from the root of the real tree to , and is its splay root with no right child.
Proof. Let the loop visit , where is the parent pointer of after the splay of . We show by induction on that after the step at (lines L3 to L5), (L) holds, and the splay tree of holds the path from the top of the old path of down to , ordered by depth.
For , after line L3 is the splay root of its path by Lemma 1. Its right subtree holds the vertices of below . Line L4 makes that subtree a separate splay tree. Its sequence is the part of below , a vertical path whose top is a child of , and its root keeps the parent pointer , so (L2) holds for it. The tree of now holds the part of from its top to . The aggregates of are recomputed, so (L3) holds.
For , the splay root of the tree built so far has parent pointer , which by (L2) is the real parent of the top of . So the path in starts at a child of . After line L3, is the root of its splay tree, whose sequence is a path through . Line L4 makes the part of below a separate splay tree with path-parent , as in the base case, and makes the right subtree of . The sequence of the tree of is now the part of from its top to , then , which is a vertical path ordered by depth because the top of is a child of . Line L4 also sets the parent of to , now as a splay edge, and the aggregates of are recomputed.
The loop ends when the parent pointer is nothing, so by (L2) the top of the last path is the root of the real tree. Then the splay tree of holds the path from the root to . The last splay, line L6, moves to the splay root; since is the deepest vertex of the sequence, it has no right child.
Lemma 3 (make root). After MAKE-ROOT, (L) holds for the same tree rooted at .
Proof. Let be the path from the old root to . Rooting at instead of changes the parent of from to for , makes parentless, and keeps every other parent. By Lemma 2 the splay tree of holds exactly , and line L8 reverses its sequence to , which is a vertical path of the new rooted tree, top first. Its top has no parent, and the parent pointer of is nothing, as (L2) needs. Every other splay tree has a top that is not on the path (each is in the tree of ), so the parent of is unchanged, and its sequence is a path that avoids except possibly at its parent, so its parent relations are unchanged. A reversal bit does not change any aggregate of a sum or a maximum.
Theorem. After each operation, (L) holds for the current forest, and each query returns the value of its definition.
Proof. At the start every vertex is a splay tree of its own with no parent pointer, which satisfies (L). Lemmas 1 to 3 cover splay, access and make root.
Find root (lines L9 and L10). After the access, the splay tree of holds the path from the real root to , and its leftmost vertex in the symmetric order with bits applied is the first vertex of the sequence, the real root. The walk pushes bits on its way down, so it reads the right children. The final splay keeps (L) by Lemma 1.
Connected. Two vertices are in the same tree if and only if they have the same real root.
Link (lines L11 and L12) with and in different trees. After MAKE-ROOT, by Lemmas 2 and 3, is the real root of its tree and the splay root of a tree whose sequence starts at . The access of keeps (L) and does not touch the tree of . In the new forest, is the parent of and all other parents are kept. Setting the parent pointer of to makes (L2) hold for the splay tree of , whose top is ; the other splay trees keep their tops and parents.
Cut (lines L13 and L14) with a forest edge. After MAKE-ROOT and ACCESS, by Lemma 2 the splay tree of holds the path from the root to , which is , with as splay root without a right child. So the tree has exactly two vertices and is the left child of . Line L14 makes a splay tree of its own with no parent pointer: is the real root of its new tree, as (L2) needs. The splay tree of is now , with no parent pointer, and is the root of its new tree. Every other splay tree keeps its top, and the real parent of each top is unchanged, since only the edge between and was removed. The aggregates of are recomputed.
Path sum and path maximum (lines L15 and L16). After MAKE-ROOT and ACCESS, by Lemma 2 the splay tree with root holds exactly the path from to , and by (L3) the aggregates at are those of this path.
Set value accesses , so is a splay root, and recomputes only the aggregates of , which are the only ones that contain its value.
Lowest common ancestor. After MAKE-ROOT and ACCESS, the splay tree that holds the root has the sequence of the path from to . Run the loop of an access of . Every step before the last one splays a vertex whose splay tree does not contain , so these steps do not change ; the last step visits a vertex of , since the loop ends at the splay tree that contains the real root. By the induction in Lemma 2, is an ancestor of (or itself), and lies on the path from to , so is a common ancestor. The vertex below on the path from to , if any, is the top of a different preferred path, so it is not on the path from to . Hence no deeper common ancestor exists, and is the lowest common ancestor.