efficient path range queries with point updates on a tree
-
is size of subtree of node
-
dfs while marking one child node with the largest as a heavy child
- ties are broken arbitrarily, exactly 1 heavy child if
-
edges going to heavy childs are heavy edges, ones going to other childs are light edges
-
heavy edges that connect to each other form heavy paths
-
for each node, store top of heavy path as (non-heavy childs keep themselves as )
-
can prove that at most light edges will be crossed through by doubling in size when going up
-
indexing with a dfs, first visit heavy childs, meaning heavy path indexes will be contiguous
-
build a segtree on the indexes, meaning heavy path queries can be done in (giving the other part of the )
-
trying to range query path from to can be split using lca, giving and as the ranges to find
-
when going from node to , use segtree range queries to compute value
-
add , jump to , repeat until reaching
template <typename T, typename Combine> class HLD {
private:
int n, rt, ti = 0;
vector<vector<int>> tree;
vector<int> p, sz, depth, head, pos;
T ident;
Combine combine;
SegmentTree<T, Combine> st;
void dfs_sz(int v) {
if (p[v] != -1) tree[v].erase(find(tree[v].begin(), tree[v].end(), p[v]));
for (int &u : tree[v]) {
p[u] = v;
depth[u] = depth[v] + 1;
dfs_sz(u);
sz[v] += sz[u];
if (sz[u] > sz[tree[v][0]]) swap(u, tree[v][0]);
}
}
void dfs_hld(int v) {
pos[v] = ti++;
for (int u : tree[v]) {
head[u] = u == tree[v][0] ? head[v] : u;
dfs_hld(u);
}
}
public:
HLD(vector<vector<int>> tree, int rt, T ident, Combine combine)
: n(tree.size()), rt(rt), tree(tree),
p(n, -1), sz(n, 1), depth(n), head(n), pos(n),
ident(ident), combine(combine), st(vector<T>(n, ident), ident, combine) {
head[rt] = rt;
dfs_sz(rt);
dfs_hld(rt);
}
T process(int a, int b) {
T s = ident;
for (; head[a] != head[b]; a = p[head[a]]) {
if (depth[head[b]] > depth[head[a]]) swap(a, b);
s = combine(s, st.range(pos[head[a]], pos[a]));
}
if (depth[b] > depth[a]) swap(a, b);
s = combine(s, st.range(pos[b], pos[a]));
return s;
}
void set(int i, T x) {
st.set(pos[i], x);
}
};