8.19 Link-Cut Trees

All previous tree algorithms in this chapter assume that the tree structure is fixed.

8.19 Link-Cut Trees

All previous tree algorithms in this chapter assume that the tree structure is fixed.

Nodes remain connected in the same way throughout execution.

Examples include:

  • Euler Tour
  • Heavy-Light Decomposition
  • Centroid Decomposition
  • Lowest Common Ancestor
  • Binary Lifting

These techniques are extremely powerful, but they struggle when the tree itself changes.

Suppose we need operations such as:

Cut edge (u,v)

Link node u
to node w

Query path(u,v)

The topology changes continuously.

Traditional preprocessing quickly becomes invalid.

Link-Cut Trees were designed specifically for this environment. They support dynamic forests, allowing edges to be inserted and removed while maintaining efficient path queries.

Introduced by entity["people","Daniel Sleator","Link-Cut Tree co-inventor"] and entity["people","Robert Tarjan","Link-Cut Tree co-inventor"], Link-Cut Trees remain one of the most sophisticated and influential dynamic tree data structures.

Problem

You need efficient path queries on trees whose structure changes over time.

Operations include:

link(u,v)
cut(u,v)
connected(u,v)
path query(u,v)

Rebuilding tree structures after every modification is too expensive.

Solution

Represent tree paths using self-adjusting binary trees.

The key idea is surprising:

Represent a tree as a collection of preferred paths.

Each preferred path is stored inside a Splay Tree.

When access patterns change, preferred paths change as well.

The structure reorganizes itself dynamically.

This allows updates and queries to remain logarithmic.

Discussion

At first glance, Link-Cut Trees appear unrelated to ordinary trees.

Internally, they operate on:

  • Preferred paths
  • Auxiliary trees
  • Splay Trees
  • Path rotations

The original tree is still present conceptually, but most operations occur inside these auxiliary structures.

The complexity of Link-Cut Trees comes from maintaining consistency between the two representations.

Preferred Paths

Consider:

        0
       / \\n      1   2
     /
    3
   /
  4

Suppose recent accesses repeatedly traverse:

0 → 1 → 3 → 4

This path becomes preferred.

0
|
1
|
3
|
4

The preferred path is stored as a Splay Tree.

Node:

2

belongs to a different auxiliary structure.

The decomposition changes automatically as operations occur.

Why Preferred Paths Matter

Suppose we want:

Path Sum(4,0)

The entire path already exists inside one auxiliary structure.

Instead of traversing many tree edges:

4
→ 3
→ 1
→ 0

the query becomes a binary-tree operation.

This is where the efficiency originates.

Core Node Structure

A simplified node representation:

type Node struct {
    Left   *Node
    Right  *Node
    Parent *Node

    Value int
    Sum   int

    Reverse bool
}

Additional fields are typically included depending on the problem.

Examples:

Maximum
Minimum
Count
Custom aggregates

The exact state depends on the desired path queries.

Maintaining Aggregates

Like Segment Trees, Link-Cut Trees maintain summaries.

func update(x *Node) {
    x.Sum = x.Value

    if x.Left != nil {
        x.Sum += x.Left.Sum
    }

    if x.Right != nil {
        x.Sum += x.Right.Sum
    }
}

Whenever rotations occur, aggregates are recomputed.

This allows path queries to execute efficiently.

Splay Trees

Link-Cut Trees rely heavily on Splay Trees.

A Splay Tree is a self-adjusting binary search tree.

Frequently accessed nodes move closer to the root.

Operations include:

Zig
Zig-Zig
Zig-Zag

rotations.

These rotations maintain logarithmic amortized complexity.

Without Splay Trees, Link-Cut Trees would not work.

Access Operation

The most important primitive is:

access(x)

Conceptually:

Expose path
from root
to x

After access:

root → x

becomes the preferred path.

Future operations can work directly on this exposed path.

Most Link-Cut Tree operations begin with access.

Making a Node the Root

Traditional rooted trees have a fixed root.

Link-Cut Trees allow rerooting.

func makeRoot(x *Node)

Conceptually:

Old Root
     ↓

     x

becomes

x

     ↓

Old Root

The represented tree changes orientation.

Internally, this is implemented using lazy path reversals.

To connect two trees:

link(u,v)

First:

makeRoot(u)

Then:

u.Parent = v

The two forests become one.

Complexity:

O(log n)

amortized.

Cut Operation

Removing an edge is equally important.

Suppose:

u --- v

exists.

After:

cut(u,v)

the tree splits into two components.

The operation:

  1. Exposes the path.
  2. Identifies the edge.
  3. Removes the connection.

Again:

O(log n)

amortized.

Connectivity Queries

Determining whether two nodes belong to the same tree is straightforward.

connected(u,v)

Compare roots.

findRoot(u)
findRoot(v)

If the roots match:

true

otherwise:

false

This is useful in dynamic graph algorithms.

Path Sum Queries

Suppose every node stores:

weight

Query:

Sum(u,v)

Procedure:

makeRoot(u)

access(v)

The path:

u → v

becomes exposed.

The aggregate stored at the root of the auxiliary tree immediately contains the answer.

No explicit path traversal is required.

Path Maximum Queries

The same framework supports:

Maximum(u,v)

Store:

Max int

instead of:

Sum int

Update aggregates during rotations.

The query logic remains unchanged.

This flexibility resembles Segment Trees.

Lazy Propagation

Many implementations support path updates.

Examples:

Add value to path

Assign value to path

Reverse path

Lazy propagation is used internally.

The idea is identical to the lazy Segment Trees discussed earlier.

Pending updates move downward only when necessary.

Dynamic Forests

Link-Cut Trees maintain:

Forest

rather than:

Single Tree

At any moment:

Tree A

Tree B

Tree C

may coexist.

Operations can connect or separate them dynamically.

This capability is one reason Link-Cut Trees appear in advanced graph algorithms.

Minimum Spanning Trees

One famous application involves dynamic minimum spanning trees.

Suppose:

Add edge
Remove edge
Query MST weight

continuously.

Link-Cut Trees help maintain path information inside the spanning forest.

Many dynamic graph algorithms rely on this capability.

Network Management

Consider a communication network.

Operations:

Connect routers

Disconnect routers

Query latency

Query bottlenecks

The topology changes frequently.

Recomputing tree structures from scratch would be expensive.

Link-Cut Trees support these operations efficiently.

Heavy-Light Decomposition assumes a static tree.

Link-Cut Trees support dynamic trees.

Feature HLD Link-Cut
Static paths Excellent Excellent
Dynamic links No Yes
Dynamic cuts No Yes
Complexity Simpler Much harder
Implementation Moderate Advanced

If the tree never changes, HLD is usually preferable.

If the topology changes continuously, Link-Cut Trees become attractive.

Amortized Complexity

Link-Cut Trees rely on amortized analysis.

Individual operations may occasionally cost more.

Across a long sequence of operations:

Operation Complexity
Access O(log n) amortized
Link O(log n) amortized
Cut O(log n) amortized
Query O(log n) amortized

The amortized guarantee comes from Splay Tree theory.

Many data structures have a simple mental model.

Examples:

Heap
→ priority queue

Trie
→ prefixes

Segment Tree
→ intervals

Link-Cut Trees combine multiple ideas:

  • Trees
  • Splay Trees
  • Lazy propagation
  • Path decomposition
  • Amortized analysis

The interaction among these concepts creates significant implementation complexity.

Even experienced programmers often require extensive testing to produce correct implementations.

Common Mistakes

A common mistake is forgetting lazy propagation during rotations.

Pending reversals must be pushed before structural changes occur.

Another mistake is confusing:

Represented tree

with:

Auxiliary tree

They are different structures.

Operations on one affect the other indirectly.

A third mistake is assuming worst-case logarithmic complexity. The guarantees are amortized, not per-operation worst-case bounds.

Finally, many implementations update local pointers correctly but forget to recompute aggregate values afterward.

Every rotation must maintain auxiliary information consistently.

Takeaway

Link-Cut Trees support efficient path queries and structural modifications in dynamic forests. By representing preferred paths with Splay Trees and reorganizing those paths as access patterns change, they provide logarithmic amortized complexity for linking, cutting, rerooting, and querying. Although significantly more complex than static-tree techniques such as Heavy-Light Decomposition, they remain one of the most powerful tools for dynamic tree and graph algorithms.