题目背景
UPDATE : 最后一个点时间空间已经放大
标题即题意
有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集)
题目描述
如题,你需要维护这样的一个长度为 N N N 的数组,支持如下几种操作
-
在某个历史版本上修改某一个位置上的值
- 访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)
输入输出格式
输入格式:输入的第一行包含两个正整数 N,M N, M N,M, 分别表示数组的长度和操作的个数。
第二行包含N N N个整数,依次为初始状态下数组各位的值(依次为 ai a_i ai,1≤i≤N 1 \leq i \leq N 1≤i≤N)。
接下来M M M行每行包含3或4个整数,代表两种操作之一(i i i为基于的历史版本号):
-
对于操作1,格式为vi 1 loci valuei v_i \ 1 \ {loc}_i \ {value}_i vi 1 loci valuei,即为在版本vi v_i vi的基础上,将 aloci a_{ {loc}_i} aloci 修改为 valuei {value}_i valuei
- 对于操作2,格式为vi 2 loci v_i \ 2 \ {loc}_i vi 2 loci,即访问版本vi v_i vi中的 aloci a_{ {loc}_i} aloci的值
输出包含若干行,依次为每个操作2的结果。
输入输出样例
输入样例#1:
5 1059 46 14 87 410 2 10 1 1 140 1 1 570 1 1 884 2 40 2 50 2 44 2 12 2 21 1 5 91
输出样例#1:
598741878846
主席树水题
用主席树维护一下每次数组的版本就行
1 #include2 #include 3 #include 4 #include 5 using namespace std; 6 const int N=1000000; 7 struct Node 8 { 9 int val;10 Node *ch[2];11 }S[N*20],*pos=S;12 Node *root[N+5];13 int a[N+5],b[N+5],n,m,sz,rem[N+5];14 void build(Node* &rt,int l,int r)15 {16 rt=++pos;17 if (l==r) 18 {rt->val=a[l];19 return;20 }21 int mid=(l+r)/2;22 build(rt->ch[0],l,mid);23 build(rt->ch[1],mid+1,r);24 }25 void insert(Node* &rt,int l,int r,int k,int w)26 {27 Node *x=rt;28 rt=++pos;29 rt->ch[0]=x->ch[0];30 rt->ch[1]=x->ch[1];31 if (l==r) 32 {rt->val=w;33 return;34 }35 int mid=(l+r)/2;36 if (k<=mid) insert(rt->ch[0],l,mid,k,w);37 else insert(rt->ch[1],mid+1,r,k,w);38 }39 int query(Node* rt,int l,int r,int k)40 {41 if (l==r) return rt->val;42 int mid=(l+r)/2;43 if (mid>=k) return query(rt->ch[0],l,mid,k);44 else return query(rt->ch[1],mid+1,r,k);45 }46 int main()47 { int i,j,x,y,k,p,v,w;48 cin>>n>>m;49 for (i=1;i<=n;i++)50 {51 scanf("%d",&a[i]);52 b[i]=a[i];53 }54 build(root[0],1,n);55 for (i=1;i<=m;i++)56 {57 scanf("%d%d",&p,&v);58 if (v==1)59 {60 scanf("%d%d",&k,&w);61 root[i]=root[p];62 insert(root[i],1,n,k,w);63 }64 else 65 {66 scanf("%d",&k);67 root[i]=root[p];68 printf("%d\n",query(root[i],1,n,k));69 }70 }71 }