[洛谷P3919]【模板】可持久化数组(可持久化线段树/平衡树)

题目大意:

你需要维护这样的一个长度为 N 的数组,支持如下几种操作

  1. 在某个历史版本上修改某一个位置上的值

  2. 访问某个历史版本上的某一位置的值

此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)

解题思路:很明显,本题需要用到可持久化数据结构。主席树即可。

主要思路就是,维护线段树,对每个节点进行标号。

这样做的好处是:由于之前版本的树是不会改变的,而本题只有单点查询,因此最多只会有$log_2 n$个节点的信息进行改变。进行标号以后,如果某棵子树没有改变,则直接将原来的编号保存下来即可,省时间又省空间。

对于题目的第一种操作,只要保存历史版本根节点的编号即可(整棵树没变化),然后单点查询。

对于题目的第二种操作,相当于单点修改,每次记录该节点的原编号和现编号,然后对于没有变化的一个子树就可以直接保存,有编化的修改即可。

说一说此题坑我的地方:本题对于不同数据范围,空间分配是不一样的(最低128MB,最高512MB),而我直接开了数组,导致被卡空间MLE。使用指针分配内存的方式成功解决此问题(代码第55~59行)。

C++ Code:

#include<cstdio>
#include<cstring>
#include<cctype>
#define N 1000005
int n,m,rt[N],cnt,Q,p;
int *ld,*rd,*d;
inline int readint(){
	char c=getchar();
	bool b=false;
	for(;!isdigit(c);c=getchar())b=c=='-';
	int d=0;
	for(;isdigit(c);c=getchar())d=(d<<3)+(d<<1)+(c^'0');
	return b?-d:d;
}
inline void putint(int d){
	if(d==0)putchar('0');else{
		if(d<0)putchar('-'),d=-d;
		int w=1;
		for(;w<=d;w*=10);
		for(w/=10;w;w/=10)
		putchar((d/w%10)^'0');
	}
	putchar('\n');
}
void build_tree(int l,int r,int o){
	if(l==r){
		d[o]=readint();
		return;
	}
	int mid=(l+r)>>1;
	build_tree(l,mid,ld[o]=++cnt);
	build_tree(mid+1,r,rd[o]=++cnt);
}
void query(int l,int r,int o){
	if(l==r)putint(d[o]);else{
		int mid=(l+r)>>1;
		if(Q<=mid)query(l,mid,ld[o]);else
		query(mid+1,r,rd[o]);
	}
}
void change(int l,int r,int old,int now){
	if(l==r)d[now]=p;else{
		int mid=(l+r)>>1;
		if(Q<=mid){
			rd[now]=rd[old];
			change(l,mid,ld[old],ld[now]=++cnt);
		}else{
			ld[now]=ld[old];
			change(mid+1,r,rd[old],rd[now]=++cnt);
		}
	}
}
int main(){
	n=readint(),m=readint();
	if(n<=150000){
		d=new int[N<<2];ld=new int[N<<2];rd=new int[N<<2];
	}else{
		d=new int[N*20];ld=new int[N*20];rd=new int[N*20];
	}
	memset(rt,0,sizeof rt);
	memset(ld,0,sizeof ld);
	memset(rd,0,sizeof rd);
	build_tree(1,n,rt[0]=cnt=1);
	for(int i=1;i<=m;++i){
		int v=readint(),opt=readint();
		Q=readint();
		if(opt==2)query(1,n,rt[i]=rt[v]);else{
			rt[i]=++cnt;
			p=readint();
			change(1,n,rt[v],rt[i]);
		}
	}
	return 0;
}

 

  

 

posted @ 2017-11-28 16:40  Mrsrz  阅读(222)  评论(0编辑  收藏  举报