📌  相关文章
📜  动态细分树:具有点更新的范围总和的在线查询(1)

📅  最后修改于: 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$ 并将其加入到树中,否则递归到其子节点中,并更新当前节点的值。

总结

动态细分树通过可持久化的方式维护了一个区间求和的数据结构,并支持单点修改操作。这种数据结构具有非常高的灵活性和可扩展性,可以在多种算法中得到广泛应用。