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

[BZOJ3196]二逼平衡树

时间:2017-10-06 10:29:03      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:modify   efi   merge   def   线段树   ima   ++   条件   nbsp   

人生第一次写树套树

 

这题是区间上的数值操作,所以我们用区间数据结构套数值数据结构

我选择了线段树套splay

其实就是对于线段树的每个节点$x$,若它代表的区间为$[l,r]$,则在这个线段树节点上建一棵含$A_{l\cdots r}$的splay

对$1$操作:直接按线段树的方式把$[l,r]$分为一些区间,在每个区间内找比$k$小的数的个数,最后$+1$即可

对$2$操作:二分答案,将$1$操作作为二分条件

对$3$操作:按线段树单点修改的方式,每到一个线段树节点就在当前的splay上删除$A_pos$再插入$k$

对$4$操作:按线段树的方式分割区间,找每个区间内$k$的前驱,最后取最大值为答案

对$5$操作:按线段树的方式分割区间,找每个区间内$k$的后继,最后取最小值为答案

 

interesting

技术分享

#include<stdio.h>
int root[200010],a[50010],ch[1600010][2],fa[1600010],siz[1600010],v[1600010],tot,n,*rt;
void rot(int x){
	int y,z,B,f;
	y=fa[x];
	z=fa[y];
	if(y==*rt)*rt=x;
	f=(ch[y][0]==x);
	B=ch[x][f];
	fa[x]=z;
	fa[y]=x;
	if(B)fa[B]=y;
	ch[x][f]=y;
	ch[y][f^1]=B;
	if(ch[z][0]==y)ch[z][0]=x;
	if(ch[z][1]==y)ch[z][1]=x;
	z=siz[x];
	siz[x]=siz[y];
	siz[y]-=(z-siz[B]);
}
void splay(int x){
	int y,z;
	while(x!=*rt){
		y=fa[x];
		z=fa[y];
		if(y==*rt)
			rot(x);
		else{
			if((ch[y][0]==x&&ch[z][0]==y)||(ch[y][1]==x&&ch[z][1]==y)){
				rot(y);
				rot(x);
			}else{
				rot(x);
				rot(x);
			}
		}
	}
}
int _insert(int&x,int val){
	if(x==0){
		tot++;
		x=tot;
		v[x]=val;
	}
	siz[x]++;
	int k=x;
	if(val<v[x]){
		k=_insert(ch[x][0],val);
		fa[ch[x][0]]=x;
	}
	if(val>v[x]){
		k=_insert(ch[x][1],val);
		fa[ch[x][1]]=x;
	}
	return k;
}
void insert(int&x,int val){
	splay(_insert(x,val));
}
void build(int l,int r,int x){
	rt=root+x;
	for(int i=l;i<=r;i++)insert(root[x],a[i]);
	if(l==r)return;
	int mid=(l+r)>>1;
	if(l<=mid)build(l,mid,x<<1);
	if(mid<r)build(mid+1,r,x<<1|1);
}
int max(int a,int b){return a>b?a:b;}
int getrank(int x,int val){
	if(x==0)return 0;
	if(val<v[x])return getrank(ch[x][0],val);
	if(val>v[x])return max(getrank(ch[x][1],val),0)+siz[x]-siz[ch[x][1]];
	return siz[ch[x][0]];
}
int getrank(int L,int R,int val,int l,int r,int x){
	if(L<=l&&r<=R){
		rt=root+x;
		return getrank(root[x],val);
	}
	int mid=(l+r)>>1,ans=0;
	if(L<=mid)ans+=getrank(L,R,val,l,mid,x<<1);
	if(mid<R)ans+=getrank(L,R,val,mid+1,r,x<<1|1);
	return ans;
}
int getkth(int l,int r,int k){
	int L,R,mid,ans;
	L=-100000000;
	R=100000000;
	while(L<=R){
		mid=(L+R)>>1;
		if(getrank(l,r,mid,1,n,1)+1<=k){
			L=mid+1;
			ans=mid;
		}else
			R=mid-1;
	}
	return ans;
}
void merge(int a,int b){
	if(a==0){
		*rt=b;
		return;
	}
	*rt=a;
	if(b==0)return;
	while(ch[a][1])a=ch[a][1];
	splay(a);
	ch[a][1]=b;
	siz[a]+=siz[b];
	fa[b]=a;
}
void erase(int x,int val){
	if(val==v[x]){
		splay(x);
		if(siz[x]-siz[ch[x][0]]-siz[ch[x][1]]>1){
			siz[x]--;
			return;
		}
		fa[ch[x][0]]=fa[ch[x][1]]=0;
		siz[x]=0;
		merge(ch[x][0],ch[x][1]);
		ch[x][0]=ch[x][1]=0;
		return;
	}
	if(val<v[x])erase(ch[x][0],val);
	if(val>v[x])erase(ch[x][1],val);
}
void modify(int pos,int val,int l,int r,int x){
	rt=root+x;
	erase(root[x],a[pos]);
	insert(root[x],val);
	if(l==r)return;
	int mid=(l+r)>>1;
	if(pos<=mid)
		modify(pos,val,l,mid,x<<1);
	else
		modify(pos,val,mid+1,r,x<<1|1);
}
#define inf 1000000000
int presc(int x,int val){
	int ans=-inf;
	while(x){
		if(v[x]<val){
			ans=v[x];
			x=ch[x][1];
		}else
			x=ch[x][0];
	}
	return ans;
}
int presc(int L,int R,int val,int l,int r,int x){
	if(L<=l&&r<=R)return presc(root[x],val);
	int ans=-inf,mid=(l+r)>>1;
	if(L<=mid)ans=max(ans,presc(L,R,val,l,mid,x<<1));
	if(mid<R)ans=max(ans,presc(L,R,val,mid+1,r,x<<1|1));
	return ans;
}
int nexsc(int x,int val){
	int ans=inf;
	while(x){
		if(v[x]>val){
			ans=v[x];
			x=ch[x][0];
		}else
			x=ch[x][1];
	}
	return ans;
}
int min(int a,int b){return a<b?a:b;}
int nexsc(int L,int R,int val,int l,int r,int x){
	if(L<=l&&r<=R)return nexsc(root[x],val);
	int ans=inf,mid=(l+r)>>1;
	if(L<=mid)ans=min(ans,nexsc(L,R,val,l,mid,x<<1));
	if(mid<R)ans=min(ans,nexsc(L,R,val,mid+1,r,x<<1|1));
	return ans;
}
int main(){
	int m,i,op,l,r,k;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d",a+i);
	build(1,n,1);
	while(m--){
		scanf("%d%d%d",&op,&l,&r);
		if(op!=3)scanf("%d",&k);
		if(op==1)printf("%d\n",getrank(l,r,k,1,n,1)+1);
		if(op==2)printf("%d\n",getkth(l,r,k));
		if(op==3){
			modify(l,r,1,n,1);
			a[l]=r;
		}
		if(op==4)printf("%d\n",presc(l,r,k,1,n,1));
		if(op==5)printf("%d\n",nexsc(l,r,k,1,n,1));
	}
}

[BZOJ3196]二逼平衡树

标签:modify   efi   merge   def   线段树   ima   ++   条件   nbsp   

原文地址:http://www.cnblogs.com/jefflyy/p/7630582.html

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