📅  最后修改于: 2023-12-03 14:50:24.934000             🧑  作者: Mango
动态细分树 (Dynamic Segment Tree) 是一种支持区间加值和区间求和的数据结构。与静态线段树不同,动态细分树可以支持动态地增删节点。
动态细分树采用可持久化的方式实现。即,每删除或修改一个节点时,原来的树不会被修改,而是新建一棵树,并在其基础上进行修改。这样,每一颗树都是完整的,操作时不会影响到已有的树。
对于一颗某个版本的动态细分树 $T$,我们可以得到其任意区间 $[l,r]$ 的和:
int query(int l, int r, int v, int tl = 0, int tr = N - 1) {
if (l > r) return 0;
if (l == tl && r == tr) return T[v].sum;
push(v);
int tm = tl + tr >> 1;
return query(l, min(r, tm), T[v].left, tl, tm) +
query(max(l, tm + 1), r, T[v].right, tm + 1, tr);
}
其中 $T[v]$ 表示版本 $v$ 对应的树的根节点,$T[v].sum$ 表示以 $v$ 所指节点为根节点的树的所有节点数之和。
对于某个版本 $v$ 的动态细分树 $T$,我们可以将节点 $p$ 处的值修改为 $x$:
void modify(int p, int x, int &v, int tl = 0, int tr = N - 1) {
if (tl == tr) {
T[++cnt] = T[v], T[cnt].sum += x;
v = cnt;
} else {
push(v);
int tm = tl + tr >> 1;
if (p <= tm)
modify(p, x, T[v].left, tl, tm);
else
modify(p, x, T[v].right, tm + 1, tr);
T[v].sum = T[T[v].left].sum + T[T[v].right].sum;
}
}
其中 $cnt$ 记录已生成的版本数。若当前节点为叶子节点,我们新建一个节点,将其值设置为 $x$ 并将其加入到树中,否则递归到其子节点中,并更新当前节点的值。
动态细分树通过可持久化的方式维护了一个区间求和的数据结构,并支持单点修改操作。这种数据结构具有非常高的灵活性和可扩展性,可以在多种算法中得到广泛应用。