How do link-cut trees achieve O(logn) amortized per operation? The answer lies in two interlocking ideas.
Preferred-path decomposition. Every node in the represented forest has at most one preferred child — whichever child was most recently accessed. The preferred children chain together into preferred paths, partitioning the forest into disjoint paths. When you access a node, you may change some preferred edges, but Sleator and Tarjan proved that the total number of preferred-edge changes across any sequence of m operations is O(mlogn).
Auxiliary splay trees. Each preferred path is stored in a splay tree keyed by depth. A splay tree is a self-adjusting BST that moves every accessed node to the root in O(logn) amortized time. Because the represented paths are short on average (by the preferred-path argument), the auxiliary trees stay balanced enough to keep every operation logarithmic.
The operations:
- access(v) — makes v the root of its auxiliary tree and splays all ancestors, re-routing preferred paths. This is the core primitive; everything else builds on it.
- link(u, v) — connects two separate trees by making u a child of v; O(logn) amortized.
- cut(v) — removes the edge from v to its parent, splitting one tree into two; O(logn) amortized.
- find-root(v) — returns the root of the tree containing v; O(logn) amortized.
- path-aggregate(u, v) — computes a fold (sum, max, min…) over all edges or nodes on the u–v path; O(logn) amortized.
The amortized guarantee is proved with a potential function: Φ=∑vlog(size of subtree rooted at v). Each operation pays for itself plus a bounded decrease in potential, so the total cost over any sequence is O(mlogn).
This was proven by Sleator and Tarjan in their 1983 paper "A Data Structure for Dynamic Trees" (STOC 1983, later in JCSS 1985). It remains the fastest known structure for this class of problems under the comparison model. See also dynamic shortest paths for a related application.
Comments
Loading comments...