Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Heavy-Light Decomposition for Range Queries on Trees

Tech May 17 2

Dynamic operations that mix path updates and queries on a tree defeat simple prefix‑sum or difference‑based preprocessing. Heavy‑light decomposition (HLD) assigns each vertex to a heavy path and gives every path, as well as every complete subtree, a contiguous interval in a preorder. By flattening these intervals onto a segment tree, HLD reduces both path and subtree queries to standard range queries.

Core Concepts

Choose a rooted tree. For each node, the heavy child is the child with the largest subtree; ties are broken arbitrarily. All other children are light children. An edge to a heavy child is a heavy edge, and an edge to a light child is a light edge. A heavy path is a maximal chain formed by consecutive heavy edges. Every leaf that is not a heavy child forms a one‑node heavy path.

Building the Decomposition (Two DFS)

Two depth‑first traversals collect the information needed to map the tree to a segment tree.

First DFS — Subtree Sizes and Heavy Child

Record the parent, depth, subtree size, and heavy child for each vertex.

int parent[N], depth[N], sz[N], heavy[N];
vector<int> adj[N];

void dfs1(int u, int p) {
  parent[u] = p;
  depth[u] = depth[p] + 1;
  sz[u] = 1;
  int max_sz = 0;
  for (int v : adj[u]) {
    if (v == p) continue;
    dfs1(v, u);
    sz[u] += sz[v];
    if (sz[v] > max_sz) {
      max_sz = sz[v];
      heavy[u] = v;
    }
  }
}

Second DFS — Heavy Path Labels and Segment Tree Positions

Assign each vertex a position pos[u] in the segment tree, store the reverse mapping rev[pos], and record the head of its current heavy path.

int head[N], pos[N], rev[N], timer;

void dfs2(int u, int h) {
  head[u] = h;
  pos[u] = ++timer;
  rev[timer] = u;
  if (heavy[u])                     // continue the heavy path
    dfs2(heavy[u], h);
  for (int v : adj[u]) {
    if (v == parent[u] || v == heavy[u]) continue;
    dfs2(v, v);                     // start a new heavy path
  }
}

Path and Subtree Operations

Once the positions are assigned,192 every heavy path corresponds to a contiguous range [pos[head[x]], pos[x]]. Likewise, the subtree rooted at x corresponds to the interval [pos[x], pos[x] + sz[x] - 1].

Lowest Common Ancestor (LCA)

While head[x] != head[y], move the vertex with the deeper head upward: let x become parent[head[x]]. Afterwards, the LCA is the vertex with the smaller depth.

int lca(int x, int y) {
  while (head[x] != head[y]) {
    if (depth[head[x]] < depth[head[y]]) swap(x, y);
    x = parent[head[x]];
  }
  return depth[x] < depth[y] ? x : y;
}

Path Queries / Updates

To query or update a path between u and v, jump up the heavy chains similarly to the LCA, and apply the15 segment tree operation on the interval [pos[head[u]], pos[u]] whenever head[u] != head[v]. After the loop,16 a final operation on the range between pos[u] and pos[v] handles the remanider.

void update_path(int u, int v, int val) {
  while (head[u] != head[v]) {
    if (depth[head[u]] < depth[head[v]]) swap(u, v);
    segtree_update(pos[head[u]], pos[u], val);
    u = parent[head[u]];
  }
  if (depth[u] > depth[v]) swap(u, v);
  segtree_update(pos[u], pos[v], val);
}

Subtree Operations

Because the pos values of a subtree are consecutive, a subtree query or update is a single segment tree call:

void update_subtree(int x, int val) {
  segtree_update(pos[x], pos[x] + sz[x] - 1, val);
}

Notes on Changing the Root

if the root of the tree is changed, the heavy‑child relationships may completely change, requiring a new decomposition. In rare situations where17 frequent rerooting is needed, Euler‑tour techniques or Link‑Cut trees are more suitable.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.