题目背景
UPDATE : 最后一个点时间空间已经放大
标题即题意
有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集)
题目描述
如题,你需要维护这样的一个长度为 NN 的数组,支持如下几种操作
-
在某个历史版本上修改某一个位置上的值
-
访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)
输入格式
输入的第一行包含两个正整数 N, MN,M, 分别表示数组的长度和操作的个数。
第二行包含NN个整数,依次为初始状态下数组各位的值(依次为 a_iai,1 leq i leq N1≤i≤N)。
接下来MM行每行包含3或4个整数,代表两种操作之一(ii为基于的历史版本号):
-
对于操作1,格式为v_i 1 {loc}_i {value}_ivi 1 loci valuei,即为在版本v_ivi的基础上,将 a_{{loc}_i}aloci 修改为 {value}_ivaluei
-
对于操作2,格式为v_i 2 {loc}_ivi 2 loci,即访问版本v_ivi中的 a_{{loc}_i}aloci的值,生成一样版本的对象应为vi
输出格式
输出包含若干行,依次为每个操作2的结果。
输入输出样例
输入 #1
5 10 59 46 14 87 41 0 2 1 0 1 1 14 0 1 1 57 0 1 1 88 4 2 4 0 2 5 0 2 4 4 2 1 2 2 2 1 1 5 91
输出 #1
View Code
59 87 41 87 88 46
可持久化线段树
// luogu-judger-enable-o2 #include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define pb push_back #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) typedef pair<int,int>pii; ////////////////////////////////// const int N=2e6+10; int t[N<<5],ncnt,T[N<<5],lson[N<<5],rson[N<<5]; void up(int x,int v,int l,int r,int pre,int &pos) { pos=++ncnt; lson[pos]=lson[pre];rson[pos]=rson[pre]; if(l==r){t[pos]=v;return ;} int m=(l+r)>>1; if(x<=m)up(x,v,l,m,lson[pre],lson[pos]); else up(x,v,m+1,r,rson[pre],rson[pos]); } int qsum(int x,int l,int r,int pos) { if(l==r)return t[pos]; int m=l+r>>1; if(x<=m) return qsum(x,l,m,lson[pos]); else return qsum(x,m+1,r,rson[pos]); } int a,b,c,d,x; int main() { int n,m;scanf("%d%d",&n,&m); rep(i,1,n) { scanf("%d",&x);up(i,x,1,n,T[0],T[0]); } rep(i,1,m) { scanf("%d%d%d",&a,&b,&c); if(b==1) { scanf("%d",&d); up(c,d,1,n,T[a],T[i]); } else { T[i]=T[a];//lson[T[i]]=lson[T[a]];rson[T[i]]=rson[T[a]];t[T[i]]=t[T[a]]; printf("%d ",qsum(c,1,n,T[a])); } } return 0; }