📅  最后修改于: 2023-12-03 15:28:55.493000             🧑  作者: Mango
须藤放置[1.4]是一种高效计算树的信息的数据结构,旨在解决树的一些常见问题,如子树和、LCA查询、路径信息等。
跳跃子树是须藤放置中的一个重要概念,指的是将一个节点的所有子孙节点分成若干个块,每个块大小不超过 $\sqrt{n}$($n$为节点的总数),并将这些块用一棵特殊的树(跳跃树)组织起来。
首先,需要定义一个结构体表示树的节点信息,一般包括父节点、子节点、深度等基本属性,同时还需要定义一个节点的额外信息,如子树和、路径和等。这个结构体的定义可以根据任务需求而定。
struct Node {
int fa, dep, sz, son, top;
// 子树信息
int sum, lazy;
// 其他信息
};
定义完结构体后,需要将子树分块,根据块的大小计算出需要多少块。这里以设定块大小为 $\sqrt{n}$ 为例:
int sz[maxn], blo[maxn], blk, num;
void dfs1(int u) {
sz[u] = 1;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (v == fa[u]) continue;
fa[v] = u, dep[v] = dep[u] + 1;
dfs1(v);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
blo[u] = tp;
if (!tp) tp = ++num;
if (!son[u]) return;
dfs2(son[u], tp);
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (v == fa[u] || v == son[u]) continue;
dfs2(v, 0);
}
}
接下来,需要建立跳跃树,将所有块按照深度从浅到深插入,每个块的父亲为其同层相邻的块中最浅的一个。
struct Tree {
int l, r, ct, len;
// 其他信息
} tree[maxn];
void build(int rt, int L, int R) {
tree[rt].l = L, tree[rt].r = R, tree[rt].ct = rt, tree[rt].len = R - L + 1;
if (L == R) return;
int mid = L + R >> 1;
if (mid - L + 1 <= blk) build(rt, L, mid), build(rt + (mid - L + 1), mid + 1, R);
else {
build(rt + 1, L, mid);
for (int i = L; i <= R; i += blk) build(rt + (i - L + 1) / blk, i, min(R, i + blk - 1));
}
}
void insert() {
for (int i = num, lca; i > 1; i--) {
lca = LCA(tree[i].l, tree[i].r);
if (blo[lca] == blo[tree[i].l]) tree[i].ct = tree[i + 1].ct, tree[i].len = tree[i + 1].len;
else {
int k = ++num;
if (!tree[i].len) tree[i].len = lca == tree[i].l ? dep[tree[i].r] : dep[tree[i].l];
int fa = (i + tree[i + 1].ct) >> 1;
int l = tree[i].l, r = (blo[l] == blo[lca] ? lca - 1 : lca);
tree[num] = (Tree){l, r, fa, dep[r] - dep[l] + 1};
}
}
}
跳跃树建立之后,就可以使用跳跃树查询节点信息、子树信息、路径信息等了。
int query(int u) {
int res = 0;
while (blo[u]) {
int fa = tree[blo[u]].ct;
if (fa) res += tree[fa].sum + (tree[fa].len - tree[blo[u]].len) * tree[fa].lazy;
else res += tree[blo[u]].sum + (dep[u] - dep[tree[blo[u]].l]) * tree[blo[u]].lazy;
u = fa ? tree[fa].l - 1 : fa;
}
return res + Tree[1].sum;
}
void modify(int x, int y, int val, int op) {
while (blo[x] != blo[y]) {
if (dep[x] < dep[y]) swap(x, y);
int fa = tree[blo[x]].ct;
if (op) add(tree[blo[x]].l, x, val), add(tree[fa].l, x, -val);
else dec(tree[blo[x]].l, x, val), dec(tree[fa].l, x, -val);
x = fa ? tree[fa].l - 1 : fa;
}
if (op) add(x, y, val);
else dec(x, y, val);
}