标签:can 完全 tps new 实现 == 复杂度 链接 upd
学习了一段时间的可持久化数据结构,感觉自己的脑子不太够用。。。。
好吧,先从最基本的看起
可持久化数组
你需要维护这样的一个长度为 N 的数组,支持如下几种操作
1.在某个历史版本上修改某一个位置上的值
2.访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)
一个很暴力的想法是将所有的版本都存下来,然后每次修改是复制一遍
这样可以O(1)查询,但是要O(N)修改,而且空间复杂度。。。。。
可以发现每次修改只会对一个位置产生影响,那我们为什么每次都要讲所有的位置进行复制呢?
我们利用可持久化线段树来解决可持久化数组的问题
维护n个单点修改单点查询的线段树
为了利用重复的空间
每次修改时,我们就创立一个新的节点
然后使得新的根可以访问到该节点
这样就实现了可持久化数组
right,left数组储存左右儿子的编号,t数组储存线段树节点的信息
r数组储存根节点的编号
不同的根节点可以访问不同的版本
注意一下,right,left,t数组一般空间都要开到20到30倍
# include<cstring> # include<iostream> # include<cstdio> # include<cmath> # include<algorithm> const int mn = 1000005; int n,m; int cnt; int left[mn*20],right[mn*20],r[mn],t[mn*20]; int build(int l,int r) { int root=++cnt; if(l==r) { scanf("%d",&t[root]); return root; } int mid=l+r>>1; left[root]=build(l,mid); right[root]=build(mid+1,r); return root; } void query(int rt,int l,int r,int x) { if(l==r) { printf("%d\n",t[rt]); return ; } int mid=l+r>>1; if(x<=mid) query(left[rt],l,mid,x); else query(right[rt],mid+1,r,x); } int update(int rt,int l,int r,int pos,int x) { int root=++cnt; if(l==r) { t[root]=x; return root; } left[root]=left[rt],right[root]=right[rt]; int mid=l+r>>1; if(pos<=mid) left[root]=update(left[rt],l,mid,pos,x); else right[root]=update(right[rt],mid+1,r,pos,x); return root; } int main() { int x,y,opt,z; scanf("%d%d",&n,&m); build(1,n); r[0]=1; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&opt); if(opt==1) { scanf("%d%d",&y,&z); r[i]=update(r[x],1,n,y,z); } else { scanf("%d",&y); r[i]=r[x]; query(r[x],1,n,y); } } return 0; }
博主是弱弱,不对的地方还请神犇指出
标签:can 完全 tps new 实现 == 复杂度 链接 upd
原文地址:https://www.cnblogs.com/logeadd/p/8890374.html