分尸(树)
重链剖分
思路
考虑将一个节点的儿子中所在子树最大的一个儿子作为重儿子,相连的边为重边,每次延重儿子划分划出来的链我们称之为重链。
对于一条链如果往上跳,必然是个轻边,所以必然存在一个重儿子的字数大于当前链所在子树,所以没往上条链,子树大小至少为原来两倍,所以时间复杂度为 \(logn\)。
code
void DFS(int x, int fa) {
sz[x] = 1;
for (int i : g[x]) {
if (i == fa) continue;
dep[i] = dep[x] + 1, DFS(i, x), sz[x] += sz[i], gfa[i] = x, (sz[son[x]] < sz[i]) && (son[x] = i);
}
}
void S(int x, int fa, int to) {
top[x] = to, dfn[x] = ++cnt, mxdfn[x] = dfn[x];
if (son[x]) S(son[x], x, to), mxdfn[x] = max(mxdfn[x], mxdfn[son[x]]);
for (int i : g[x]) {
if (i == fa || i == son[x]) continue;
S(i, x, i), mxdfn[x] = max(mxdfn[i], mxdfn[x]);
}
}