题目背景
标题即题意
有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集)
题目描述
如题,你需要维护这样的一个长度为 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: 复制
59 87 41 87 88 46
(妥妥的权值线段树)
最终图只是最后一棵线段树的样子,之前的各个线段树依旧在保存着
直接暴力每一个状态,然后记录,超时空!
每一次只修改一个点,不是吗?
于是,我们只要修改这一个点,然后把这条链记录下来,不就可以了?233
这不是熟悉的主席树吗?
是的!
建一棵空树,然后以原数组插入,之后对每一次修改进行一次加链操作
然后查询就可以了。
直接代码:
#include<bits/stdc++.h> using namespace std; const int maxn=20000001; int n,m,cnt; int a[maxn]; int dis[maxn];//有些不同的就是,我们要记录下来每一次改的值 int rs[maxn]; int ls[maxn]; int rt[maxn]; int build(int l,int r) { int root=++cnt; if(l==r) { dis[root]=a[l];//像极了线段树233 return root;//还是要记录根的 } int mid=l+r>>1; ls[root]=build(l,mid); rs[root]=build(mid+1,r); return root; } int updata(int l,int r,int root,int x,int k) { int newroot=++cnt; if(l==r) { dis[newroot]=x;//如果到叶子了就记录一下新的值 return newroot;//还是要返回根的 } ls[newroot]=ls[root]; rs[newroot]=rs[root]; int mid=l+r>>1; if(k<=mid)ls[newroot]=updata(l,mid,ls[newroot],x,k); else rs[newroot]=updata(mid+1,r,rs[newroot],x,k); return newroot; } void query(int l,int r,int root,int x) { if(l==r) { printf("%d ",dis[root]);//直接输出,不用差分 return ; } int mid=l+r>>1; if(x<=mid)query(l,mid,ls[root],x);//直接跑,不用差分了 else query(mid+1,r,rs[root],x);//直接跑,不用差分了 } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]);//这次没有这么多神仙操作 } rt[0]=build(1,n);//建树 for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); if(y==1) { int flag; scanf("%d",&flag); rt[i]=updata(1,n,rt[x],flag,z);//同kth,加链,记录根节点 } if(y==2) { rt[i]=rt[x]; query(1,n,rt[x],z);//查询 } } return 0; }
(完)