Treap

Treap=Tree+Heap
Treap是 排序树 的结合。
是一个二叉排序树。
(即对于每一个点,其左子树所有的值小于它,右子树所有的值大于它)

#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
#define INF 0x3FFFFFFF
#define MAXN 500000
#define MOD 1000037
struct node{
    int key,fix,cnt,siz;
    node *ch[2];
}tree[MAXN+5];
/*
key:当前节点的值
fix:优先级
cnt:该节点值重复个数
siz:子孙个数
ch:左右子树的指针
*/
node *root,*NIL,*ncnt;
//root:根 NIL:空 ncnt:总结点个数
void Init(){
    NIL=&tree[0];
    NIL->ch[0]=NIL->ch[1]=NIL;
    NIL->key=-INF,NIL->fix=INF;
    NIL->cnt=NIL->siz=0;
    ncnt=&tree[1];
    root=NIL;
}//初始化
inline node * NewNode(int val){
    node *p=++ncnt;
    p->key=val,p->fix=rand()%MOD;
    p->cnt=p->siz=1;
    p->ch[0]=p->ch[1]=NIL;
    return p;
}//开拓新一个节点
void PushUp(node *x){
    x->siz=x->ch[0]->siz+x->ch[1]->siz+x->cnt;
}//递左右子孙的个数
void Rotate(node *&x,int d){
    node *y=x->ch[!d];
    x->ch[!d]=y->ch[d];
    y->ch[d]=x;
    x=y;
    PushUp(x->ch[d]);
    PushUp(x);
}//旋转
void Insert(node *&rt,int val){
    if(rt==NIL){
        rt=NewNode(val);
        return ;
    }
    if(rt->key==val){
        rt->cnt++,rt->siz++;
        return ;
    }
    int d=val>=rt->key;
    Insert(rt->ch[d],val);
    if(rt->ch[d]->fix<rt->fix)
        Rotate(rt,!d);
    PushUp(rt);
}//插入
void Delete(node *&rt,int val){
    if(rt->ch[0]==NIL&&rt->ch[1]==NIL){
        if(rt->key==val){
            rt->cnt--,rt->siz--;
            if(rt->cnt==0)rt=NIL;
        }
        return ;
    }
    if(rt->key==val)
        if(rt->cnt>1){
            rt->cnt--,rt->siz--;
            return ;
        }
        else{
            int d=rt->ch[0]->fix<rt->ch[1]->fix;
            Rotate(rt,d);
            Delete(rt->ch[d],val);
        }
    else{
        int d=val>rt->key;
        Delete(rt->ch[d],val);
    }
    PushUp(rt);
}//删除
int GetRank(node* rt,int val){
    if(rt==NIL)return 1;
    if(val==rt->key)return rt->ch[0]->siz+1;
    if(val<rt->key)
        return GetRank(rt->ch[0],val);
	else
		return GetRank(rt->ch[1],val)+rt->ch[0]->siz+rt->cnt;
}//查找该值在当前树中值排第几(从小到大)
node *Select(node *rt,int k){
	if(rt==NIL)return NIL;
	if(rt->ch[0]->siz>=k)return 
		Select(rt->ch[0],k);
	if(rt->ch[0]->siz+rt->cnt>=k)
		return rt;
	return Select(rt->ch[1],k-rt->ch[0]->siz-rt->cnt);
}//查找排第几的数(从小到大)
node *FindPrev(int val){
	int k=GetRank(root,val);
	node *p=Select(root,k-1);
	return p;
}//找前驱
node *FindNext(int val){
	int k=GetRank(root,val+1);
	node *p=Select(root,k);
	return p;
}//找后继
int main(){
	int n,x,op,k;
	node*p;
	Init();
	scanf("%d",&n);
	while(n-->0){
		scanf("%d%d",&op,&x);
		switch(op){
			case 1:
				Insert(root,x);break;
			case 2:
				Delete(root,x);break;
			case 3:
				k=GetRank(root,x);
				printf("%d\n",k);break;
			case 4:
				p=Select(root,x);
				printf("%d\n",p->key);break;
			case 5:
				p=FindPrev(x);
				printf("%d\n",p->key);break;
			case 6:
				p=FindNext(x);
				printf("%d\n",p->key);break;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值