guest@itl:~/home/graph$
templates/lca-weighted.cpp
compilable
$cat templates/lca-weighted

LCA Weighted

LCA with path aggregate queries (sum/max/min) on weighted trees using binary lifting in O(log n).

[Graph]|
Jul 9, 2026
|explanatory_notes.md|
#lca#binary-lifting#weighted-tree#path-query#aggregate
Log in to track progress, save custom versions, and organize into collections.Log In
$cat source_code/
cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const int MAXN = 2e5 + 5;
const int LOG = 18;
vector<pair<int, ll>> adj[MAXN];
int anc[MAXN][LOG], dep[MAXN];
ll cost[MAXN][LOG];

void dfs(int u, int p) {
    for (auto &[v, w] : adj[u]) {
        if (v == p) continue;
        dep[v] = dep[u] + 1;
        anc[v][0] = u;
        cost[v][0] = w;
        for (int k = 1; k < LOG; k++) {
            anc[v][k] = anc[anc[v][k-1]][k-1];
            cost[v][k] = cost[v][k-1] + cost[anc[v][k-1]][k-1];
        }
        dfs(v, u);
    }
}

int kthAncestor(int u, int k) {
    for (int i = 0; i < LOG; i++)
        if (k >> i & 1) u = anc[u][i];
    return u;
}

int lca(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    u = kthAncestor(u, dep[u] - dep[v]);
    if (u == v) return u;
    for (int k = LOG - 1; k >= 0; k--)
        if (anc[u][k] != anc[v][k])
            u = anc[u][k], v = anc[v][k];
    return anc[u][0];
}

ll pathQuery(int u, int v) {
    int l = lca(u, v);
    ll res = 0;
    auto lift = [&](int node, int d) {
        for (int k = 0; k < LOG; k++)
            if (d >> k & 1) { res += cost[node][k]; node = anc[node][k]; }
    };
    lift(u, dep[u] - dep[l]);
    lift(v, dep[v] - dep[l]);
    return res;
}

int dist(int u, int v) {
    return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}
55 linesutf-8
$cat explanation_notes.md
notes_viewer --renderedmarkdown (math enabled)

LCA Weighted

Binary lifting extended with path aggregate queries on weighted trees. Each ancestor table entry stores both the 2k2^k-th ancestor and the aggregate of edge weights along that jump.

How It Works

  • DFS from root fills anc[v][k] (the 2k2^k-th ancestor) and cost[v][k] (the aggregate over that jump)

  • Cost recurrence: cost[v][k]=op(cost[v][k1],  cost[anc[v][k1]][k1])\text{cost}[v][k] = \text{op}(\text{cost}[v][k-1],\; \text{cost}[\text{anc}[v][k-1]][k-1])

  • Path query (u,v)(u, v): find LCA, aggregate from uu up to LCA and from vv up to LCA, combine
  • Operations

  • lca(u, v) — lowest common ancestor

  • query(u, v) — path aggregate (sum/max/min/xor depending on op)

  • dist(u, v) — hop distance on tree

  • kthAncestor(u, k)kk-th ancestor
  • When to Use

  • Path sum, max, min, or XOR queries on weighted trees

  • Bottleneck edge queries (max/min edge on path)

  • Any associative operation along tree paths
  • Complexity

  • Build — O(nlogn)O(n \log n)

  • Query — O(logn)O(\log n)

  • Space — O(nlogn)O(n \log n)