关于非旋转treap的学习

非旋转treap的操作基于split和merge操作,其余操作和普通平衡树一样,复杂度保证方式与旋转treap差不多,都是基于一个随机的参数,这样构出的树树高为\(logn\)

split

作用:将原平衡树分为排名为\([1,k]\),\([k+1,n]\)的两棵平衡树
实现:
1.如果\(x\)左儿子的子树大小\(size[l]==k\),那么\(x\)左儿子即为\([1,k]\)这个平衡树的根,\(x\)本身为另一颗平衡树的根
2.如果\(x\)左儿子的子树大小\(size[l]+1==k\),那么\(x\)\([1,k]\)这个平衡树的根,\(x\)右儿子为另一颗平衡树的根
3.如果是上述情况,直接把左儿子或右儿子接上去就好
4.否则,递归处理,直到出现这两种情况位置

inline void split(int x,int k,int &a,int &b){
	if(!k){a=0;b=x;return ;}
	int l=ch[x][0],r=ch[x][1];
	if(sz[l]==k)ch[x][0]=0,a=l,b=x;
	else if(sz[l]+1==k)ch[x][1]=0,a=x,b=r;
	else if(sz[l]>k)split(l,k,a,ch[x][0]),b=x;
	else split(r,k-sz[l]-1,ch[x][1],b),a=x;
	upd(x);
}

merge

作用:将两棵平衡树合并,合并后参数满足\(heap\)的性质,且满足平衡树性质.
实现:
我们强制\(merge(x,y)\)\(x\)的所有节点的关键字都小于所有\(y\)的关键字,根据关键字合并即可.

inline int merge(int x,int y){
	if(!x||!y)return x+y;
	if(key[x]>key[y]){
		ch[x][1]=merge(ch[x][1],y);
		upd(x);
		return x;
	}
	else{
		ch[y][0]=merge(x,ch[y][0]);
		upd(y);
		return y;
	}
}

insert

\(x\)的前驱为界,拆原树为两棵树,将左树合并到\(x\),再将\(x\)合并到右树

inline void ins(int x){
	v[++cnt]=x;key[cnt]=rand();sz[cnt]=1;
	int l,r;
	split(rt,rank(x)-1,l,r);
	rt=merge(merge(l,cnt),r);
}

delet

\(x\)为界\(split\)原树,删除\(x\)后再合并左右子树

inline void Delet(int x){
	int l,r;
	split(rt,x,l,r);
	split(l,x-1,l,x);
	rt=merge(l,r);
}

标记下放

只需在\(merge\),\(split\),\(kth\),\(rank\)函数前下放即可

完整代码:

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=100005;
int ch[N][2],sz[N],key[N],cnt=0,v[N],rt;
inline void upd(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
inline void split(int x,int k,int &a,int &b){
	if(!k){a=0;b=x;return ;}
	int l=ch[x][0],r=ch[x][1];
	if(sz[l]==k)ch[x][0]=0,a=l,b=x;
	else if(sz[l]+1==k)ch[x][1]=0,a=x,b=r;
	else if(sz[l]>k)split(l,k,a,ch[x][0]),b=x;
	else split(r,k-sz[l]-1,ch[x][1],b),a=x;
	upd(x);
}
inline int merge(int x,int y){
	if(!x||!y)return x+y;
	if(key[x]>key[y]){
		ch[x][1]=merge(ch[x][1],y);
		upd(x);
		return x;
	}
	else{
		ch[y][0]=merge(x,ch[y][0]);
		upd(y);
		return y;
	}
}
inline int rank(int k){
	int x=rt,ret=1;
	while(x){
		if(k<=v[x])x=ch[x][0];
		else ret+=sz[ch[x][0]]+1,x=ch[x][1];
	}
	return ret;
}
inline int kth(int k){
	int x=rt,sum;
	while(x){
		sum=sz[ch[x][0]];
		if(sum==k-1)return v[x];
		if(sum>=k)x=ch[x][0];
		else x=ch[x][1],k-=sum+1;
	}return 0;
}
inline void ins(int x){
	v[++cnt]=x;key[cnt]=rand();sz[cnt]=1;
	int l,r;
	split(rt,rank(x)-1,l,r);
	rt=merge(merge(l,cnt),r);
}
inline void Delet(int x){
	int l,r;
	split(rt,x,l,r);
	split(l,x-1,l,x);
	rt=merge(l,r);
}
void work()
{
	int n,op,x;
	scanf("%d",&n);
	while(n--){
		scanf("%d%d",&op,&x);
		if(op==1)ins(x);
		else if(op==2)Delet(rank(x));
		else if(op==3)printf("%d\n",rank(x));
		else if(op==4)printf("%d\n",kth(x));
		else if(op==5)printf("%d\n",kth(rank(x)-1));
		else if(op==6)printf("%d\n",kth(rank(x+1)));
	}
}

int main()
{
	freopen("pp.in","r",stdin);
	freopen("pp.out","w",stdout);
	work();
	return 0;
}

posted @ 2017-12-23 21:46  PIPIBoss  阅读(282)  评论(0编辑  收藏  举报