维护长度为 N 的数组,可支持如下操作:
- 在某个历史版本上修改某一个位置上的值
- 访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本,版本编号即为当前操作的编号(版本0表示初始状态数组)
- 可持久化线段树(主席树)
#include<cstdio>
#include<iostream>
#define MAXN 1000010
using namespace std;
int n,m,a[MAXN],rt[MAXN],r,t,p,v,tot;
struct Node{
int l,r,v;
}tree[MAXN*20];
int build(int k,int l,int r){
k=++tot;
if(l==r){
tree[k].v=a[l];
return tot;
}
int m=(l+r)/2;
tree[k].l=build(tree[k].l,l,m);
tree[k].r=build(tree[k].r,m+1,r);
return k;
}
int clone(int k){
tree[++tot]=tree[k];
return tot;
}
int update(int k,int l,int r,int p,int v){
k=clone(k);
if(l==r)tree[k].v=v;
else{
int m=(l+r)/2;
if(p<=m)tree[k].l=update(tree[k].l,l,m,p,v);
else tree[k].r=update(tree[k].r,m+1,r,p,v);
}
return k;
}
int query(int k,int l,int r,int p){
if(l==r)return tree[k].v;
else{
int m=(l+r)/2;
if(p<=m)return query(tree[k].l,l,m,p);
else return query(tree[k].r,m+1,r,p);
}
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
rt[0]=build(0,1,n);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&r,&t,&p);
if(t==1){ // 修改
scanf("%d",&v);
rt[i]=update(rt[r],1,n,p,v);
}else{
printf("%d\n",query(rt[r],1,n,p));
rt[i]=rt[r];
}
}
}