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).
#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 -th ancestor and the aggregate of edge weights along that jump.
How It Works
anc[v][k] (the -th ancestor) and cost[v][k] (the aggregate over that jump)Operations
lca(u, v) — lowest common ancestorquery(u, v) — path aggregate (sum/max/min/xor depending on op)dist(u, v) — hop distance on treekthAncestor(u, k) — -th ancestor