Purpose: Maintain a forest under link and cut, supporting path queries and updates in amortized. Better known as link-cut trees β€” Sleator and Tarjan, 1983.

Operations

OperationMeaning
makeTree(v)create a single-vertex tree
link(u, v)attach tree of (as root) under
cut(v)detach from its parent
findRoot(v)root of β€˜s tree
pathAggregate(u, v)sum / min / max along the path
pathUpdate(u, v, x)add to every edge on the path
lca(u, v)lowest common ancestor
evert(v)make the root (reverse a path)

All amortized.

The Structure: preferred paths + splay trees

  1. Decompose the tree into preferred paths β€” vertex-disjoint downward paths covering every vertex (like HLD, but the decomposition changes dynamically with access patterns).
  2. Store each preferred path in a splay tree, keyed implicitly by depth.
  3. Link the splay trees together with path-parent pointers: the root of one path’s splay tree points to the vertex it hangs off in the parent path (a one-way pointer, invisible to the splay tree itself).

access(v) β€” the one primitive

Everything is built on access(v), which makes the path from the root to a single preferred path with at its bottom:

access(v):
    splay(v)
    detach v's right subtree (deeper vertices leave the preferred path)
    while v has a path-parent w:
        splay(w)
        replace w's right subtree with v's splay tree
        rotate v up

Then:

  • findRoot(v) = access(v), then walk left to the shallowest vertex;
  • pathAggregate(u,v) = evert(u), access(v), read the splay tree’s aggregate;
  • link(u,v) = evert(u), then set β€˜s path-parent to ;
  • cut(v) = access(v), detach the left subtree.

Complexity

amortized per operation. The proof uses a heavy-light argument to bound the number of preferred-child changes at per access, plus the splay tree access lemma. It is not worst-case: a single operation can cost , though a sequence of cannot cost more than .

StructureHandlesPath aggregatesDifficulty
HLD + segment treestatic treeyesmoderate
Euler tour treelink/cutsubtree onlymoderate
Link-cut treelink/cutyeshard
Top treelink/cutyes, plus non-local infovery hard

Do you actually need it?

If the tree is static, use HLD β€” simpler, worst-case , and the segment tree gives you lazy updates for free. If updates are offline, consider offline dynamic connectivity instead. Reach for link-cut trees when the tree genuinely changes online and you need path queries.

What it unlocks

  • Dynamic connectivity in forests β€” per operation
  • Max flow speedups β€” Dinic with link-cut trees is ; see Goldberg-Tarjan
  • Online MST maintenance β€” path-max query plus edge swap
  • LCA in a changing tree
  • Offline problems in disguise β€” sometimes it is the only structure that fits

Variants / Use Cases

  • Link-Cut Tree β€” the topic page with implementation notes
  • Euler Tour Trees β€” for subtree, not path, aggregates
  • Top trees / topology trees β€” the more general framework
  • Splay trees β€” the self-adjusting BST underneath; Sleator and Tarjan invented those too