📜  持久段树|设置1(简介)(1)

📅  最后修改于: 2023-12-03 15:25:53.063000             🧑  作者: Mango

持久段树 | 设置1 (简介)

持久化数据结构的定义

现实中很多问题中,数据的存储需求是持久化的,就是说需要在改变后,能够保留以前的数据状态,而且每个状态都是有自己的编号的,这个编号便是历史版本。在这样的需求下,我们就需要设计出一些持久化数据结构。对于持久化数据结构,说白了不单单是当前数的版本,更包括了我们过去数的版本。

举个例子来说:你第一次编辑了一篇文章,第二次你发现想要回到第一次的版本,那么你就需要一个编辑器或者是一个存储器能够在当前版本不改变的情况下给你一份过去的版本。

下面我们介绍一种比较常用的持久化数据结构之一——持久化线段树。

持久化线段树简介

持久化线段树,是线段树的一个扩展,是一种能够存储历史版本的线段树。它与普通线段树最大的区别就是能够在每次修改操作时对整棵线段树同时进行修改,同时还能够保证原先版本不变。

下面是持久化线段树的一些基本操作:

build

这个操作类似于线段树的建树,用于建立持久化线段树的根节点。

update

这个操作类似于线段树的单点修改,用于在一棵线段树的某一个版本中修改某个位置上的数值。

query

这个操作类似于线段树的区间查询,用于在一棵线段树的某一个版本中查询某个区间的数值。

history

这个操作用于得到线段树的某个版本的历史信息,包括某个版本的建树操作和修改操作。

总结

了解了持久化数据结构的定义和持久化线段树的概念和操作,你应该能够更好地应对一些问题,利用持久化数据结构来解决问题。

代码示例:

    // C++代码
    const int MAXN = 1e5 + 10;
    int T[MAXN << 5], L[MAXN << 5], R[MAXN << 5], cnt = 0;

    void build(int &p, int l, int r) {
        p = ++cnt;
        T[p] = 0;
        if (l == r) return;
        int mid = (l + r) >> 1;
        build(L[p], l, mid);
        build(R[p], mid + 1, r);
    }

    void update(int &p, int q, int l, int r, int pos, int val) {
        p = ++cnt;
        T[p] = T[q] + val;
        L[p] = L[q], R[p] = R[q];
        if (l == r) return;
        int mid = (l + r) >> 1;
        if (pos <= mid) update(L[p], L[q], l, mid, pos, val);
        else update(R[p], R[q], mid + 1, r, pos, val);
    }

    int query(int p, int q, int l, int r, int ql, int qr) {
        if (ql <= l && qr >= r) return T[p] - T[q];
        int mid = (l + r) >> 1, res = 0;
        if (ql <= mid) res += query(L[p], L[q], l, mid, ql, qr);
        if (qr > mid) res += query(R[p], R[q], mid + 1, r, ql, qr);
        return res;
    }