码迷,mamicode.com
首页 > 其他好文 > 详细

可持久化练习

时间:2020-07-23 23:30:13      阅读:112      评论:0      收藏:0      [点我收藏+]

标签:sum   def   tree   info   线段   拷贝   alt   src   ffffff   

先挖坑,过几天填

https://www.luogu.com.cn/training/14535#problems

可持久化数组

P3919 【模板】可持久化线段树 1(可持久化数组)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int nodecnt;
int tree[maxn*30],ls[maxn*30],rs[maxn*30];
int root[maxn],a[maxn];
int maketree(int rt,int l,int r){//建树
	rt=++nodecnt;
	if(l==r){
		tree[rt]=a[l];
		return nodecnt;
	}
	int mid=(l+r)>>1;
	ls[rt]=maketree(ls[rt],l,mid);
	rs[rt]=maketree(rs[rt],mid+1,r);
	return rt;
}
int get(int rt){//拷贝原节点信息
	nodecnt++;
	tree[nodecnt]=tree[rt];
	ls[nodecnt]=ls[rt];
	rs[nodecnt]=rs[rt];
	return nodecnt;
}
int update(int rt,int l,int r,int x,int val){
	rt=get(rt);
	if(l==r){
		tree[rt]=val;
	}else{
		int mid=(l+r)>>1;
		if(x<=mid)ls[rt]=update(ls[rt],l,mid,x,val);
		else rs[rt]=update(rs[rt],mid+1,r,x,val);
	}
	return rt;
}
int query(int rt,int l,int r,int x){//查询操作
	if(l==r)return tree[rt];
	int mid=(l+r)>>1;
	if(x<=mid)return query(ls[rt],l,mid,x);
	return query(rs[rt],mid+1,r,x);
}
inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();}
   while(ch>=‘0‘&&ch<=‘9‘) s=s*10+ch-‘0‘,ch=getchar();
   return s*w;
}

int main(){
	int n,m;
	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	root[0]=maketree(0,1,n);//建原始版本线段树
	for(int i=1;i<=m;i++){
		int rt,op,x;
		rt=read(),op=read(),x=read();
		if(op==1){
			int y;
			y=read();
			root[i]=update(root[rt],1,n,x,y);//构建新节点线段树的log(n)个节点
		}
		else{
			printf("%d\n",query(root[rt],1,n,x));
			root[i]=root[rt];//建立新版本,当前版本和查询版本一致
		}
	}
} 

可持久化线段树

P3834 【模板】可持久化线段树 2(主席树)

#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
int p;
int nodecnt;//实现动态开点
int a[maxn],b[maxn],n,m;//a是原数组,b是离散化数组
int size[maxn<<5],root[maxn],rs[maxn<<5],ls[maxn<<5];//size记录节点大小,root记录每一棵树的根,ls-->左儿子,rs-->右儿子
void build(int &rt,int l,int r){//间一棵空树
//引用,顺便修改,实现动态开点
	rt=++nodecnt;
	if(l==r){return;}
	int mid=(l+r)>>1;
	build(ls[rt],l,mid);
	build(rs[rt],mid+1,r);
}
int get(int rt){//继承该节点原版本的全部信息
	nodecnt++;
	ls[nodecnt]=ls[rt];
	rs[nodecnt]=rs[rt];
	size[nodecnt]=size[rt]+1;
	return nodecnt;
}
int modify(int rt,int l,int r){//通过rt(上一棵树的根节点)构建当前树
	rt=get(rt);//继承
	if(l==r)return rt;//返回当前节点的编号
	int mid=(l+r)>>1;
	if(p<=mid)ls[rt]=modify(ls[rt],l,mid);//记录下面节点返回的编号
	else rs[rt]=modify(rs[rt],mid+1,r);
	return rt;//返回当前节点的编号
}
int query(int u,int v,int l,int r,int k){
	int ans;
	int mid=(l+r)>>1;
	int x=size[ls[v]]-size[ls[u]];//记录在l到r中左子树(l~mid)添加的数字的个数
	if(l==r)return l;//到叶子节点,返回答案
	if(x>=k)ans=query(ls[u],ls[v],l,mid,k);//大于则说明左子树添加的节点数大于k,那么区间第k小在左侧
	else ans=query(rs[u],rs[v],mid+1,r,k-x);//区间第k小在右侧
	return ans;
}
int main(){
	int l,r,k,q,ans;
    scanf("%d%d", &n, &m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];//离散化数组
	}
	sort(b+1,b+1+n);//排序
	q=unique(b+1,b+n+1)-b-1;//去重
	build(root[0],1,q);//构建空树
	for(int i=1;i<=n;i++){
		p=lower_bound(b+1,b+q+1,a[i])-b;//查找a[i]离散化后的大小(在b数组中的位置)
		root[i]=modify(root[i-1],1,q);//根据第i-1棵线段树构建第i棵线段树
	}
	while(m--){
		int l,r,k;
		scanf("%d%d%d",&l,&r,&k);
		int ans=query(root[l-1],root[r],1,q,k);//查询l,r中的区间k小
		//和前缀和类似,从树l-1到r查询
		printf("%d\n",b[ans]);//输出原数据
	}
	
}

可持久化平衡树

P3835 【模板】可持久化平衡树
(维护历史版本的修改查询,这里提供线段树做法)

对值域开+动态开点

调了好长时间,一直28分,后来发现,竟然可以删除不存在的节点????(大雾)-->>加判断

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=5e5+10;
int size[maxn*30];
int ls[maxn*30],rs[maxn*30],root[maxn];
int nodecnt;
int get(int rt){
	++nodecnt;
	ls[nodecnt]=ls[rt];
	rs[nodecnt]=rs[rt];
	size[nodecnt]=size[rt];
	return nodecnt;
}
void add(int &rt,int l,int r,int x,int v){
	if(rt!=0)rt=get(rt);
	else if(rt==0)rt=++nodecnt;
	size[rt]+=v;
	if(l==r){
		if(size[rt]<0)size[rt]=0;	
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)add(ls[rt],l,mid,x,v);
	else add(rs[rt],mid+1,r,x,v);
	size[rt]=size[ls[rt]]+size[rs[rt]];
}
int getnum(int rt,int l,int r,int x){
	if(size[rt]==0||x>r){
		return size[rt];
	}
	int mid=(l+r)>>1;
	if(x<=mid)return getnum(ls[rt],l,mid,x);
	return size[ls[rt]]+getnum(rs[rt],mid+1,r,x);
}
int getk(int rt,int l,int r,int k){
	if(l==r)return l;
	int mid=(l+r)>>1;
	if(size[ls[rt]]>=k)return getk(ls[rt],l,mid,k);
	return getk(rs[rt],mid+1,r,k-size[ls[rt]]);
}
signed main(){
	int n;
	scanf("%lld",&n);
	root[0]=++nodecnt;
	for(int i=1;i<=n;i++){
		int rt,op,x;
		scanf("%lld%lld%lld",&rt,&op,&x);
		root[i]=root[rt];
		if(op==1){
			add(root[i],-1e9,1e9+1,x,1);
		}
		if(op==2){
			add(root[i],-1e9,1e9+1,x,-1);
		}
		if(op==3){
			printf("%lld\n",getnum(root[i],-1e9,1e9+1,x)+1);
		}
		if(op==4){
			printf("%lld\n",getk(root[i],-1e9,1e9+1,x));
		}
		if(op==5){
			int ans=getnum(root[i],-1e9,1e9+1,x);
			if(ans==0)printf("%d\n",-0x7fffffff);
			else printf("%lld\n",getk(root[i],-1e9,1e9+1,ans));
		}
		if(op==6){
			int ans=getk(root[i],-1e9,1e9+1, getnum(root[i],-1e9,1e9+1,x +1)+1);
			if(ans==1e9+1)printf("%d\n",0x7fffffff);
			else printf("%lld\n",ans);
		}
	}

}

对数组开+离线操作+离散化

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int nodecnt;
struct node{
	int v,op,x;
}temp[maxn];
int tmp[maxn],tail;
int rs[maxn*32],ls[maxn*32],size[maxn*32],root[maxn];
int n;

void build(int &curr, int l, int r) {
    curr = ++nodecnt;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(ls[curr], l, mid);
    build(rs[curr], mid + 1, r);
}
int get(int rt){
	nodecnt++;
	ls[nodecnt]=ls[rt];
	rs[nodecnt]=rs[rt];
	size[nodecnt]=size[rt];
	return nodecnt;
}
void add(int &rt,int l,int r,int x,int v){
	rt=get(rt);
	if(l==r){
		size[rt]+=v;
		if(size[rt]<0)size[rt]=0;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)add(ls[rt],l,mid,x,v);
	else add(rs[rt],mid+1,r,x,v);
	size[rt]=size[ls[rt]]+size[rs[rt]];
}

int opuerysum(int rt,int l,int r,int x){
	if(x<l)return 0;
	if(x>=r)return size[rt];
	int mid=(l+r)>>1;
	return opuerysum(ls[rt],l,mid,x)+opuerysum(rs[rt],mid+1,r,x);
}

int opuerykth(int rt,int l,int r,int k){
	if(l==r)return l;
	int mid=(l+r)>>1;
	if(k<=size[ls[rt]])return opuerykth(ls[rt],l,mid,k);
	else return opuerykth(rs[rt],mid+1,r,k-size[ls[rt]]);
}

int opuerypre(int v,int x){
	int ans=opuerysum(root[v],1,tail,x-1);
	if(!ans)return -2147483647;
	else return tmp[opuerykth(root[v],1,tail,ans)];

}
int opuerysucc(int v,int x){
	int ans=opuerysum(root[v],1,tail,x);
	if(ans>=size[root[v]])return 2147483647;
	else return tmp[opuerykth(root[v],1,tail,ans+1)];
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&temp[i].v,&temp[i].op,&temp[i].x);
		if(temp[i].op!=4){
			tmp[++tail]=temp[i].x;
		}
	}
	sort(tmp+1,tmp+tail+1);
	tail=unique(tmp+1,tmp+tail+1)-(tmp+1);
	build(root[0],1,tail);
	for(int i=1;i<=n;i++){
		int v=temp[i].v,op=temp[i].op,x=temp[i].x;
		if(op!=4){x=lower_bound(tmp+1,tmp+tail+1,x)-tmp;}
		root[i]=root[v];
		if(op==1){	
			add(root[i],1,tail,x,1);
		}
		if(op==2){
			add(root[i],1,tail,x,-1);
		}
		if(op==3){
			printf("%d\n",opuerysum(root[i],1,tail,x-1)+1);
		}
		if(op==4){
			printf("%d\n",tmp[opuerykth(root[i],1,tail,x)]);
		}
		if(op==5){
			printf("%d\n",opuerypre(i,x));
		}
		if(op==6){
			printf("%d\n",opuerysucc(i,x));
		}
	}
	
}

可持续化Trie

P4735 最大异或和

#include<bits/stdc++.h>
using namespace std;
const int N=6e5+10;
int nodecnt;
int tree[N*24][2],latest[N*24];
int s[N],root[N],n,m;
void get(int rt,int last){
	tree[rt][1]=tree[last][1];
	tree[rt][0]=tree[last][0];
	latest[rt]=latest[last];
}
void insert(int rt,int last,int i,int k){
	get(rt,last);
	if(k<0){
		latest[rt]=i;
		return;
	}
	bool rel=s[i]>>k&1;
	tree[rt][rel]=++nodecnt;
	insert(tree[rt][rel],tree[last][rel],i,k-1);
	latest[rt]=max(latest[tree[rt][0]],latest[tree[rt][1]]);
}
int ask(int rt,int val,int k,int lim){
	if(k<0)return s[latest[rt]]^val;
	int rel=val>>k&1;
	if(latest[tree[rt][rel^1]]>=lim)
		return ask(tree[rt][rel^1],val,k-1,lim);
	else 
		return ask(tree[rt][rel],val,k-1,lim);
}
int main(){
	scanf("%d%d",&n,&m);
	latest[0]=-1;
	root[0]=++nodecnt;
	insert(root[0],0,0,23);
	for(int i=1;i<=n;i++){
		int x;scanf("%d",&x);
		s[i]=s[i-1]^x;
		root[i]=++nodecnt;
		insert(root[i],root[i-1],i,23);
	}
	for(int i=1;i<=m;i++){				
		char op;
		scanf(" %c",&op);
		if(op==‘A‘){
			int x;scanf("%d",&x);
			root[++n]=++nodecnt;
			s[n]=s[n-1]^x;
			insert(root[n],root[n-1],n,23);
		}
		else{
			int l,r,x;
			scanf("%d%d%d",&l,&r,&x);
			printf("%d\n",ask(root[r-1],x^s[n],23,l-1));
		}
		
	}
}

可持久化并查集

可持久化数组维护可持久化并查集??

#include<bits/stdc++.h>
using namespace std;
const int maxn=200050;
int n,m,nodecnt;
int dep[maxn*30],fa[maxn*30],root[maxn],rs[maxn*30],ls[maxn*30];
inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();}
   while(ch>=‘0‘&&ch<=‘9‘) s=s*10+ch-‘0‘,ch=getchar();
   return s*w;
}
void build(int &rt,int l,int r){
	if(!rt)rt=++nodecnt;
	if(l==r){fa[rt]=l;return;}
	int mid=(l+r)>>1;
	build(ls[rt],l,mid);build(rs[rt],mid+1,r);
}
void update(int &rt,int pre,int l,int r,int x,int y){
	rt=++nodecnt;
	if(l==r){
		dep[rt]=dep[pre];
		fa[rt]=y;
		return;
	}
	ls[rt]=ls[pre],rs[rt]=rs[pre];
	int mid=(l+r)>>1;
	if(x<=mid)update(ls[rt],ls[pre],l,mid,x,y);
	else update(rs[rt],rs[pre],mid+1,r,x,y);
}
int query(int rt,int l,int r,int x){
    if(l==r)return rt;
    int mid=(l+r)>>1;
    if(x<=mid)return query(ls[rt],l,mid,x);
    else return query(rs[rt],mid+1,r,x);
}
void add(int rt,int l,int r,int x){
	if(l==r){dep[rt]++;return;}
	int mid=(l+r)>>1;
	if(x<=mid)add(ls[rt],l,mid,x);
	else add(rs[rt],mid+1,r,x);
}

int find_root(int rt,int now){
	int nowx=query(rt,1,n,now);
	if(fa[nowx]==now)return nowx;
	return find_root(rt,fa[nowx]);
}
int main(){
	n=read(),m=read();
	build(root[0],1,n);
	for(int i=1;i<=m;i++){
		int op;
		op=read();
		if(op==1){
			root[i]=root[i-1];
			int x=read(),y=read();
			int fx=find_root(root[i],x),fy=find_root(root[i],y);
			if(fa[fx]==fa[fy])continue;
			if(dep[fx]>dep[fy])swap(fx,fy);
			update(root[i],root[i-1],1,n,fa[fx],fa[fy]);
			if(dep[fx]+1>dep[fy])add(root[i],1,n,fa[fy]);
		}
		if(op==2){
			int kx=read();
			root[i]=root[kx];
		}
		if(op==3){
			root[i]=root[i-1];
			int x=read(),y=read();
			int fx=find_root(root[i],x),fy=find_root(root[i],y);
			if(fa[fx]==fa[fy])puts("1");
			else puts("0");
		}
	}
}

填坑完

技术图片

可持久化练习

标签:sum   def   tree   info   线段   拷贝   alt   src   ffffff   

原文地址:https://www.cnblogs.com/soda-ma/p/13358503.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!