可持久化数组
题目描述
如题,你需要维护这样的一个长度为 $N$ 的数组,支持如下几种操作
-
在某个历史版本上修改某一个位置上的值
-
访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)
输入输出格式
输入格式:
输入的第一行包含两个正整数 $N, M$, 分别表示数组的长度和操作的个数。
第二行包含 $N$ 个整数,依次为初始状态下数组各位的值(依次为 $a_i$, $1 leq i leq N$ )。
接下来 $M$ 行每行包含3或4个整数,代表两种操作之一( $i$ 为基于的历史版本号):
-
对于操作1,格式为 $v_i 1 {loc}_i {value}_i$ ,即为在版本 $v_i$ 的基础上,将 $a_{{loc}_i}$ 修改为 ${value}_i$
-
对于操作2,格式为 $v_i 2 {loc}_i$ ,即访问版本 $v_i$ 中的 $a_{{loc}_i}$ 的值
输出格式:
输出包含若干行,依次为每个操作2的结果。
输入输出样例
说明
数据规模:
对于30%的数据: $1 leq N, M leq {10}^3$
对于50%的数据: $1 leq N, M leq {10}^4$
对于70%的数据: $1 leq N, M leq {10}^5$
对于100%的数据: $1 leq N, M leq {10}^6, 1 leq {loc}_i leq N, 0 leq v_i < i, -{10}^9 leq a_i, {value}_i leq {10}^9$
经测试,正常常数的可持久化数组可以通过,请各位放心
数据略微凶残,请注意常数不要过大
另,此题I/O量较大,如果实在TLE请注意I/O优化
询问生成的版本是指你访问的那个版本的复制
分析:
可持久化数据结构的一个好板子,这里蒟蒻用的是可持久化线段树(因为只会这个)。
每次操作的时候,复制询问的前一个状态的路径即可。另外询问操作直接把那一次的root修改为当前询问的历史版本的root。
Code:
//It is made by HolseLee on 5th Aug 2018 //Luogu.org P3919 #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<iomanip> #include<algorithm> using namespace std; const int N=1e6+7; int n,m,root[N],a[N],cnt; struct node{ int ls,rs,val; }; struct Seg{ node seg[N*20]; inline void build(int &rt,int l,int r) { rt=++cnt; if(l==r){ seg[rt].val=a[l];return; } int mid=(l+r)>>1; build(seg[rt].ls,l,mid); build(seg[rt].rs,mid+1,r); } inline void update(int &rt,int last,int l,int r,int pos,int v) { rt=++cnt; seg[rt].ls=seg[last].ls,seg[rt].rs=seg[last].rs; seg[rt].val=seg[last].val; if(l==r){ seg[rt].val=v;return; } int mid=(l+r)>>1; if(pos<=mid)update(seg[rt].ls,seg[last].ls,l,mid,pos,v); else update(seg[rt].rs,seg[last].rs,mid+1,r,pos,v); } inline int quary(int rt,int l,int r,int pos) { if(l==r)return seg[rt].val; int mid=(l+r)>>1; if(pos<=mid)return quary(seg[rt].ls,l,mid,pos); else return quary(seg[rt].rs,mid+1,r,pos); } }T; inline int read() { char ch=getchar();int num=0;bool flag=false; while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();} while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();} return flag?-num:num; } int main() { n=read();m=read(); for(int i=1;i<=n;++i)a[i]=read(); T.build(root[0],1,n); int pre,pos,value,op; for(int i=1;i<=m;++i){ pre=read();op=read();pos=read(); if(op==1){ T.update(root[i],root[pre],1,n,pos,read()); } else { printf("%d ",T.quary(root[pre],1,n,pos)); root[i]=root[pre]; } } return 0; }