HLD Algorithm

The Heavy Light Decomposition (HLD) Algorithm is an advanced tree data structure technique that is primarily used to solve problems related to path queries and modifications on weighted trees. The core idea behind HLD is to partition the given tree into several disjoint chains, each containing a sequence of connected nodes, in such a way that the tree's structure and properties are preserved. By decomposing the tree into smaller chains, we can efficiently answer queries and perform updates on entire paths or subtrees by breaking them down into smaller, manageable pieces. This decomposition allows us to reduce the complexity of operations on the tree from O(n) to O(log n), where n represents the number of nodes in the tree. The HLD Algorithm works by dividing the tree into a set of heavy and light edges based on the size of the subtrees rooted at each node. A heavy edge is one that connects a node to its child with the largest subtree, while a light edge connects a node to its other children. By selecting the heavy edges, we can create a collection of vertex-disjoint chains, where each chain can be represented as a contiguous segment in an array. This array representation enables us to leverage various data structures, such as segment trees or binary indexed trees, to efficiently perform range queries and updates on the chains. Furthermore, the algorithm ensures that the number of light edges on any given path from the root to a leaf node is limited to O(log n), which guarantees an efficient traversal of the tree. As a result, the HLD Algorithm has become a popular choice for solving complex tree-based problems in competitive programming and other computer science domains.
/************************************************************************************

    Heavy-light decomposition with segment trees in paths.
    Used for finding maximum on the path between two vertices.
    O(N) on building, O(logN ^ 2) on query. 

    Based on problem 1553 from acm.timus.ru 
    http://acm.timus.ru/problem.aspx?space=1&num=1553

************************************************************************************/

#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <cstring>
#include <cassert>
#include <utility>
#include <iomanip>

using namespace std;

const int MAXN = 105000;

struct SegmentTree {
    int * tree;
    int size;

    void init(int sz) {
        tree = new int[4 * sz];
        memset(tree, 0, 4 * sz * sizeof(int));
        size = sz;
    }

    int getMax(int v, int from, int to, int l, int r) {
        if (l > to || r < from)
            return 0;
        if (from == l && to == r)
            return tree[v];
        int mid = (from + to) / 2;
        int res = getMax(v * 2, from, mid, l, min(r, mid));
        res = max(res, getMax(v * 2 + 1, mid + 1, to, max(l, mid + 1), r));
        return res;
    }

    int getMax(int l, int r) {
        return getMax(1, 1, size, l, r); 
    }

    void update(int v, int from, int to, int pos, int val) {
        if (pos > to || pos < from)
            return;
        if (from == pos && to == pos) {
            tree[v] = val;
            return;
        }
        int mid = (from + to) / 2;
        update(v * 2, from, mid, pos, val);
        update(v * 2 + 1, mid + 1,  to, pos, val);
        tree[v] = max(tree[v * 2], tree[v * 2 + 1]);
    }

    void update(int pos, int val) {
        update(1, 1, size, pos, val);
    }
};

int n, qn;
char q;
int a, b;
int timer;
int sz[MAXN];
int tin[MAXN], tout[MAXN];    
int val[MAXN];
vector <int> g[MAXN];
int p[MAXN];
int chain[MAXN], chainRoot[MAXN];
int chainSize[MAXN], chainPos[MAXN];
int chainNum;
SegmentTree tree[MAXN];

bool isHeavy(int from, int to) {
    return sz[to] * 2 >= sz[from];
}

void dfs(int v, int par = -1) {
    timer++;
    tin[v] = timer;
    p[v] = par;
    sz[v] = 1;

    for (int i = 0; i < (int) g[v].size(); i++) {
        int to = g[v][i];
        if (to == par)
            continue;
        dfs(to, v);
        sz[v] += sz[to];
    }

    timer++;
    tout[v] = timer;
}

int newChain(int root) {
    chainNum++;
    chainRoot[chainNum] = root;
    return chainNum;
}

void buildHLD(int v, int curChain) {
    chain[v] = curChain;
    chainSize[curChain]++;
    chainPos[v] = chainSize[curChain];

    for (int i = 0; i < g[v].size(); i++) {
        int to = g[v][i];
        if (p[v] == to)
            continue;
        if (isHeavy(v, to))
            buildHLD(to, curChain);
        else
            buildHLD(to, newChain(to));
    }   
}

bool isParent(int a, int b) {
    return tin[a] <= tin[b] && tout[a] >= tout[b];
}

int getMax(int a, int b) {
    int res = 0;
    while (true) {
        int curChain = chain[a];
        if (isParent(chainRoot[curChain], b))
            break;
        res = max(res, tree[curChain].getMax(1, chainPos[a]));
        a = p[chainRoot[curChain]];
    }
    while (true) {
        int curChain = chain[b];
        if (isParent(chainRoot[curChain], a))
            break;                                          
        res = max(res, tree[curChain].getMax(1, chainPos[b]));
        b = p[chainRoot[curChain]];
    }
    int from = chainPos[a], to = chainPos[b];
    if (from > to)
        swap(from, to);
    res = max(res, tree[chain[a]].getMax(from, to));
    return res;
}


int main() {
    //assert(freopen("input.txt","r",stdin));
    //assert(freopen("output.txt","w",stdout));

    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int from, to;
        scanf("%d %d", &from, &to);
        g[from].push_back(to);
        g[to].push_back(from);
    }

    dfs(1);
    buildHLD(1, newChain(1));

    for (int i = 1; i <= chainNum; i++) {
        tree[i].init(chainSize[i]); 
    }

    scanf("%d\n", &qn);
    for (int i = 1; i <= qn; i++) {
        scanf("%c %d %d\n", &q, &a, &b);
        if (q == 'I') {
            val[a] += b;
            tree[chain[a]].update(chainPos[a], val[a]);
        }
        else {
            printf("%d\n", getMax(a, b));
        }
    }    

    return 0;
}

LANGUAGE:

DARK MODE: