P3919 【模板】可持久化数组(可持久化线段树/平衡树)
Description
如题,你需要维护这样的一个长度为 N N N 的数组,支持如下几种操作
- 在某个历史版本上修改某一个位置上的值
- 访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)
Input
输入的第一行包含两个正整数 N,M, 分别表示数组的长度和操作的个数。
第二行包含N个整数,依次为初始状态下数组各位的值(依次为 ai ,1≤i≤N )。
接下来M行每行包含3或4个整数,代表两种操作之一(i 为基于的历史版本号):
- 对于操作1,格式为vi 1 loci valuei ,即为在版本vi 的基础上,将 aloci修改为 valuei
- 对于操作2,格式为vi 2 loci ,即访问版本vi 中的 aloci 的值
Output
- 输出包含若干行,依次为每个操作2的结果。
Sample Input
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
Sample Output
59 87 41 87 88 46
Data Size
- 对于100%的数据:1≤N,M≤10^6,1≤loci≤N,0≤vi<i,−10^9≤ai,valuei≤10^9
题解:
- 主席树。
- 原来所谓的可持久化结构就是用主席树实现的啊... ...
- 这题的思路跟高级打字机一样还更简单些。
#include <iostream> #include <cstdio> #define N 1000005 using namespace std; struct T {int l,r,v;}t[N*32]; int n,m,dex; int rt[N]; int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*=f; } int build(int l,int r) { int p=++dex,mid=l+r>>1; if(l==r) {t[p].v=read();return p;} t[p].l=build(l,mid); t[p].r=build(mid+1,r); return p; } int upd(int lat,int l,int r,int pos,int val) { int p=++dex,mid=l+r>>1; t[p]=t[lat]; if(l==r) {t[p].v=val;return p;} if(pos<=mid) t[p].l=upd(t[lat].l,l,mid,pos,val); else t[p].r=upd(t[lat].r,mid+1,r,pos,val); return p; } int ask(int lat,int l,int r,int pos) { if(l==r) return t[lat].v; int mid=l+r>>1; if(pos<=mid) return ask(t[lat].l,l,mid,pos); else return ask(t[lat].r,mid+1,r,pos); } int main() { cin>>n>>m; rt[0]=build(1,n); for(int i=1;i<=m;i++) { int lat=read(),op=read(),pos=read(); if(op==1) { int val=read(); rt[i]=upd(rt[lat],1,n,pos,val); } else if(op==2) { rt[i]=rt[lat]; printf("%d\n",ask(rt[i],1,n,pos)); } } return 0; }