UPDATE : 最後一個點時間空間已經放大html
標題即題意node
有了可持久化數組,即可以實現不少衍生的可持久化功能(例如:可持久化並查集)數組
如題,你須要維護這樣的一個長度爲 NN 的數組,支持以下幾種操做ui
在某個歷史版本上修改某一個位置上的值spa
此外,每進行一次操做(對於操做2,即爲生成一個徹底同樣的版本,不做任何改動),就會生成一個新的版本。版本編號即爲當前操做的編號(從1開始編號,版本0表示初始狀態數組)code
輸入格式:htm
輸入的第一行包含兩個正整數 N, MN,M, 分別表示數組的長度和操做的個數。blog
第二行包含NN個整數,依次爲初始狀態下數組各位的值(依次爲 a_iai,1 \leq i \leq N1≤i≤N)。get
接下來MM行每行包含3或4個整數,表明兩種操做之一(ii爲基於的歷史版本號):it
對於操做1,格式爲v_i \ 1 \ {loc}_i \ {value}_ivi 1 loci valuei,即爲在版本v_ivi的基礎上,將 a_{{loc}_i}aloci 修改成 {value}_ivaluei
輸出格式:
輸出包含若干行,依次爲每一個操做2的結果。
數據規模:
對於30%的數據:1 \leq N, M \leq {10}^31≤N,M≤103
對於50%的數據:1 \leq N, M \leq {10}^41≤N,M≤104
對於70%的數據:1 \leq N, M \leq {10}^51≤N,M≤105
對於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}^91≤N,M≤106,1≤loci≤N,0≤vi<i,−109≤ai,valuei≤109
思路1:樹上dfs離線操做
#include<cstdio> #define f(c) for(int i=1;i<=c;i++) using namespace std; const int maxn = 1000009; int head[maxn],n,m,cnt,a[maxn],ans[maxn]; struct edg{int next,to;}e[maxn]; struct node{int ver,opt,pos,val;}q[maxn]; bool uuz[maxn]; int I(){int x=0,f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;'0'<=ch&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;} void add(int x,int y){e[++cnt].next=head[x];head[x]=cnt;e[cnt].to=y;} void dfs(int x){int last; q[x].opt==1?last=a[q[x].pos],a[q[x].pos]=q[x].val:ans[x]=a[q[x].pos]; for(int i=head[x];i;i=e[i].next)dfs(e[i].to); if(q[x].opt==1)a[q[x].pos]=last;} int main(){n=I();m=I();f(n)a[i]=I(); f(m){q[i].ver=I();q[i].opt=I();q[i].pos=I(); q[i].opt==1?q[i].val=I():uuz[i]=1;add(q[i].ver,i);} dfs(0);f(m)if(uuz[i])printf("%d\n",ans[i]);return 0;}
思路2:可持久化線段樹
#include<cstdio> #define f(a) for(int i=1;i<=a;i++) const int N=1000005; using namespace std; int a[N],n,q,rt[N*20]; int I(){int x=0,f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;'0'<=ch&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;} struct Persistable_Segment_Tree{ int lc[N*20],rc[N*20],val[N*20],cnt; inline void build(int &o,int l,int r){ o=++cnt;if(l==r){val[o]=a[l];return;} int mid=(l+r)>>1;build(lc[o],l,mid);build(rc[o],mid+1,r);} inline void ins(int &o,int pre,int l,int r,int q,int v){ o=++cnt;lc[o]=lc[pre];rc[o]=rc[pre];val[o]=val[pre]; if(l==r){val[o]=v;return;}int mid=(l+r)>>1; q<=mid?ins(lc[o],lc[pre],l,mid,q,v):ins(rc[o],rc[pre],mid+1,r,q,v);} inline int query(int o,int l,int r,int q){ if(l==r)return val[o];int mid=(l+r)>>1; if(q<=mid)return query(lc[o],l,mid,q); else return query(rc[o],mid+1,r,q);} }T; int main(){n=I();int m=I();f(n)a[i]=I();T.build(rt[0],1,n); f(m){int pre=I(),opt=I(),x=I(); if(opt==1){int v=I();T.ins(rt[i],rt[pre],1,n,x,v);} else printf("%d\n",T.query(rt[pre],1,n,x)),rt[i]=rt[pre];} }
思路3:主席樹
#include<cstdio> using namespace std; #define MAX 1000100 #define f(c) for(int i=1;i<=c;i++) int I(){int x=0,f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;'0'<=ch&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;} int root[MAX],a[MAX],N,M; struct Node{int l,r,ls,rs,val;}t[MAX*20]; int sum=0,tot=1; void Build(int now,int l,int r){t[now].l=l;t[now].r=r; if(l==r){t[now].val=a[l];return;} t[now].ls=++tot;int mid=(l+r)>>1; Build(tot,l,mid);t[now].rs=++tot;Build(tot,mid+1,r);} void AddNode(int now,int New,int k,int w){t[New]=t[now]; if(t[now].l==t[now].r){t[New].val=w;return;} int mid=(t[now].l+t[now].r)>>1; if(k<=mid)t[New].ls=++tot,AddNode(t[now].ls,tot,k,w); else t[New].rs=++tot,AddNode(t[now].rs,tot,k,w);} void Query(int now,int k){ if(t[now].l==t[now].r){printf("%d\n",t[now].val);return;} int mid=(t[now].l+t[now].r)>>1; k<=mid?Query(t[now].ls,k):Query(t[now].rs,k);} int main(){N=I();M=I();f(N)a[i]=I(); Build(1,1,N);root[0]=1; f(M){int v=I(),opt=I(); if(opt==1){int vv=I(),ww=I();AddNode(root[v],root[++sum]=++tot,vv,ww);} else{int vv=I();Query(root[v],vv);root[++sum]=root[v];}}return 0;}