平衡树 treap 学习笔记

平衡树 treap

平衡树本质上是维护一个有序序列 (中序遍历)
treap将随机性作用于堆性质,并通过左旋 / 右旋维护,将树高保持在O(logn)

基本操作

插入数值x
删除数值x
查询数值x的排名(若有多个相同的数,应输出最小的排名)。
查询排名为x的数值。
求数值x的前驱(前驱定义为小于x的最大的数)。
求数值x的后继(后继定义为大于x的最小的数)。

STL set没有的操作:
1、get_rank_by_key
2、get_key_by_rank

1、删除操作:
先查找需要删除的节点,将其旋转到叶子节点,直接删除叶子
2、比较rk和size找key,比较key和key找rk

AcWing 253. 普通平衡树

AcWing 265. 营业额统计

代码

const int N=1e5+10;
struct treap{
	int l,r;
	int key,val;	//平衡树排序key,大根堆val 
	int cnt,size;	//当前节点重复值个数cnt,子树size 
}t[N];
int idx,root;

int New(int key){
	t[++idx].key=key;
	t[idx].val=rand();
	t[idx].cnt=t[idx].size=1;
	return idx;
}
void pushup(int p){ t[p].size=t[t[p].l].size+t[t[p].r].size +t[p].cnt; }

void zag(int &p){					//左旋 
	int q=t[p].r;
	t[p].r=t[q].l; t[q].l=p; p=q;	
	pushup(t[p].l); pushup(p);
}
void zig(int &p){					//右旋 
	int q=t[p].l;
	t[p].l=t[q].r; t[q].r=p; p=q;
	pushup(t[p].r); pushup(p);
}

void build(){
	New(-1e9); New(1e9);
	root=1; t[1].r=2;
	pushup(root);
	if(t[2].val>t[1].val) zag(root);//
}
void insert(int &p,int key){
	if(p==0){ p=New(key); return ; }
	
	if(key==t[p].key) t[p].cnt+=1; 
	else if(key<t[p].key){
		insert(t[p].l, key);
		if(t[t[p].l].val>t[p].val) zig(p);
	}
	else if(key>t[p].key){
		insert(t[p].r, key);
		if(t[t[p].r].val>t[p].val) zag(p);
	}
	pushup(p);
}
void remove(int &p,int key){
	if(!p) return ;
	
	if(key<t[p].key) remove(t[p].l,key);
	else if(key>t[p].key) remove(t[p].r,key);
	else if(key==t[p].key){
		if(t[p].cnt>1) t[p].cnt-=1;
		else if(t[p].l || t[p].r){
			if(!t[p].r || t[t[p].l].val>t[t[p].r].val) zig(p), remove(t[p].r,key);//
			else zag(p), remove(t[p].l,key);
		}
		else p=0;//叶子节点 
	}
	pushup(p);
}

int getrk(int p,int key){
	if(!p) return 0;		
	
	if(key==t[p].key) return t[t[p].l].size+1;
	else if(key<t[p].key) return getrk(t[p].l,key);
	else return t[t[p].l].size+t[p].cnt+ getrk(t[p].r,key);
}

int getkey(int p,int rk){
	if(!p) return 1e9;
	
	if(rk<=t[t[p].l].size) return getkey(t[p].l,rk);
	else if(rk<=t[t[p].l].size+t[p].cnt) return t[p].key;
	else return getkey(t[p].r, rk-t[t[p].l].size-t[p].cnt);//
}

int getpre(int p,int key){// 二分,找<key,的max 
	if(p==0) return -1e9;
	
	if(t[p].key<key) return max( t[p].key, getpre(t[p].r,key) );//
	else return getpre(t[p].l,key);
	
//	if(key<=t[p].key) return getpre(t[p].l,key);	//若找<=key,把<=改为<,getnex对称修改 
//	else return max(t[p].key, getpre(t[p].r,key));
}
int getnex(int p,int key){// > 
	if(p==0) return 1e9;
	
	if(t[p].key>key) return min( t[p].key, getnex(t[p].l, key) );
	else return getnex(t[p].r, key);
	
//	if(key>=t[p].key) return getnex(t[p].r,key);
//	else return min(t[p].key, getnex(t[p].l,key));
}

int Work(){
	build();//哨兵 
		
	int q; cin>>q;
	while(q--){
		int op,x; scanf("%d%d",&op,&x);
		if(op==1) insert(root,x);
		else if(op==2) remove(root,x);
		else if(op==3) printf("%d\n",getrk(root,x) -1);	//由于哨兵 
		else if(op==4) printf("%d\n",getkey(root,x +1));
		else if(op==5) printf("%d\n",getpre(root,x));
		else if(op==6) printf("%d\n",getnex(root,x));
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值