Treap

简介

Treap(树堆)是一种 弱平衡 的 二叉搜索树.

Treap 的结点除了被维护的 权值()之外,还附加了一个随机的 优先级().其中,权值满足二叉搜索树性质,优先级满足堆性质(小根堆或大根堆).

其中,二叉搜索树的性质是指:

  • 左子树所有节点的权值()比父节点小.
  • 右子树所有节点的权值()比父节点大.

堆的性质是:

  • 子节点优先级()比父节点大或小(取决于是小根堆还是大根堆).

思路

通过随机的优先级使得期望深度降为 \(O(logn)\) 级别

主要操作

旋转(rotate)

原理

image.png

作用

维护堆的性质

实现

void rotate(int &p,int d){//0:左旋 1:右旋
	int tmp=ch[p][d^1];ch[p][d^1]=ch[tmp][d],ch[tmp][d]=p,p=tmp;
	pushup(ch[p][d]),pushup(p);
}

插入(insert)

原理

先确保BST的性质,再通过旋转来维护堆的性质

实现

void insert(int &p,int v){
	if(!p){create(p,v);return;}
	if(v==val[p]){cnt[p]++;pushup(p);return;}
	int d=(v>val[p]);
	insert(ch[p][d],v);
	if(rk[p]<rk[ch[p][d]]) rotate(p,d^1);
	pushup(p);
}

删除(remove)

原理

将节点移动到叶子上再删除

实现

void remove(int &p,int v){
	if(!p) return;
	if(v==val[p]){
		if(cnt[p]>1){cnt[p]--;pushup(p);return;}
		if(ls||rs){
			if(!rs||rk[ls]>rk[rs]) rotate(p,1),remove(rs,v);
			else rotate(p,0),remove(ls,v);
			pushup(p);
		}else p=0;
		return;
	}
	if(v<val[p]) remove(ls,v);
	else remove(rs,v);
	pushup(p);
}

例题

#include<bits/stdc++.h>
using namespace std;
#define ls ch[p][0]
#define rs ch[p][1]
const int N=1e6+5,inf=1e9;
int ch[N][2],val[N],cnt[N],rk[N],tot,siz[N],rt,n;
void create(int &p,int v){p=++tot,val[p]=v,cnt[p]=1,rk[p]=rand(),siz[p]=1;}
void pushup(int p){siz[p]=siz[ls]+siz[rs]+cnt[p];}
void build(){create(rt,-inf),create(ch[rt][1],inf),pushup(rt);}
void rotate(int &p,int d){
	int tmp=ch[p][d^1];ch[p][d^1]=ch[tmp][d],ch[tmp][d]=p,p=tmp;
	pushup(ch[p][d]),pushup(p);
}
void insert(int &p,int v){
	if(!p){create(p,v);return;}
	if(v==val[p]){cnt[p]++;pushup(p);return;}
	int d=(v>val[p]);
	insert(ch[p][d],v);
	if(rk[p]<rk[ch[p][d]]) rotate(p,d^1);
	pushup(p);
}
void remove(int &p,int v){
	if(!p) return;
	if(v==val[p]){
		if(cnt[p]>1){cnt[p]--;pushup(p);return;}
		if(ls||rs){
			if(!rs||rk[ls]>rk[rs]) rotate(p,1),remove(rs,v);
			else rotate(p,0),remove(ls,v);
			pushup(p);
		}else p=0;
		return;
	}
	if(v<val[p]) remove(ls,v);
	else remove(rs,v);
	pushup(p);
}
int get_rk(int p,int v){
	if(!p) return 1;
	if(val[p]==v) return siz[ls]+1;
	if(val[p]>v) return get_rk(ls,v);
	return siz[ls]+cnt[p]+get_rk(rs,v);
}
int get_val(int p,int x){
	if(!p) return inf;
	if(siz[ls]>=x) return get_val(ls,x);
	if(siz[ls]+cnt[p]>=x) return val[p];
	return get_val(rs,x-siz[ls]-cnt[p]);
}
int get_pre(int p,int v){
	int ans=0;
	while(p){
		if(val[p]<v) ans=val[p],p=rs;
		else p=ls;
	}
	return ans;
}
int get_nxt(int p,int v){
	int ans=inf;
	while(p){
		if(val[p]>v) ans=val[p],p=ls;
		else p=rs;
	}
	return ans;
}
int main(){
	build();
	cin>>n;
	while(n--){
		int op,x;cin>>op>>x;
		switch(op){
		case 1:{insert(rt,x);break;}
		case 2:{remove(rt,x);break;}
		case 3:{cout<<get_rk(rt,x)-1<<"\n";break;}
		case 4:{cout<<get_val(rt,x+1)<<"\n";break;}
		case 5:{cout<<get_pre(rt,x)<<"\n";break;}
		case 6:{cout<<get_nxt(rt,x)<<"\n";break;}
		}
	}
	return 0;
}
posted @ 2026-10-30 22:51  Rainesxiao  阅读(4)  评论(0)    收藏  举报