参考博客
可持久化数据结构:可以保留每一个历史版本,若所有版本都既可以访问又可以修改,成为完全可持久化(可以回滚到某个历史版本)
时间线:

可持久化线段树

可持久化下标线段树

题目:

模板 可持久化数组
你需要维护一个长度为N的数组,支持如下几种操作:
1.在某个历史版本上修改某一个位置上的值
2.访问某个历史版本的某一位置的值

做法:

用下标线段树维护一个数组,对于每个版本建一棵线段树->空间O(QN)
用可持久化的思想进行优化
当a[id]的值发生改变时,会影响从根[1,N]–>叶子[id,id]这条链上的所有点,其他点不会被影响,受影响的点只有logN个,所有我们没必要单独再建一个线段树,可以只建新版本的logN个点,其他点与老版本共用
如图,当a[1]发生修改时的情况

这样我们既保存了旧版本又存下新版本,根节点1(白色)对应旧版本,根节点1(红色)对应新版本,这样保存下所有历史版本,而且空间得到优化
空间O(logN)
时间O(logN)
增加边复杂度为常数

赋值节点的操作

赋值节点时直接用赋值运算符 =

Node* copyNode(Node* rt){
   
    Node *p = pool + (++top);
    pool[top] = *rt;
    return p;
}   

Node* change(Node* rt, int id, int x){
   
    Node *p = copyNode(rt);//修改时,复制沿途Node
    if(p->l==p->r){
   
        p->d = x;
        return p;
    }

    int mid = (p->l + p->r)/2;
    if(id <= mid) p->ls = change(p->ls, id, x);
    else p->rs = change(p->rs, id, x);

    return p;
}

完整代码

#include<bits/stdc++.h>
#define MAXN 1000006
using namespace std;
typedef long long ll;

int N,M;
int a[MAXN];

struct Node{
   
    int l,r,d;
    Node *ls, *rs;
} pool[30*MAXN], *rt[MAXN];

int top = 0;

Node* buildT(int l, int r){
   
    Node* p = pool + (++top);
    p->l = l; p->r = r;
    if(l==r){
   
        p->d = a[l];
        return p;
    }

    int mid = (l + r)/2;
    p->ls = buildT(l, mid);
    p->rs = buildT(mid+1, r);
    return p;
}

Node* copyNode(Node* rt){
   
    Node *p = pool + (++top);
    pool[top] = *rt;
    return p;
}

Node* change(Node* rt, int id, int x){
   
    Node *p = copyNode(rt);
    if(p->l==p->r){
   
        p->d = x;
        return p;
    }

    int mid = (p->l + p->r)/2;
    if(id <= mid) p->ls = change(p->ls, id, x);
    else p->rs = change(p->rs, id, x);

    return p;
}

int query(Node* rt, int id){
   
    if(rt->l == rt->r){
   
        return rt->d;
    }

    int mid = (rt->l + rt->r)/2;
    if(id <= mid) return query(rt->ls, id);
    else return query(rt->rs, id);
}

int main(){
   

    scanf("%d%d", &N, &M);
    for(int i=1;i<=N;i++){
   
        scanf("%d", &a[i]);
    }

    rt[0] = buildT(1,N);

    int t = 0;
    int op,id,v,x;
    while(M--){
   
        scanf("%d%d", &v, &op);//在v版本就行op操作
        if(op==1){
   
            scanf("%d%d", &id, &x);
            rt[++t] = change(rt[v], id, x);
        }
        else{
   
            scanf("%d", &id);
            rt[++t] = rt[v];
            printf("%d\n", query(rt[v], id)); 
        }
    }

    return 0;
}