【Treap模板】【指针】【luogu3369】

/*
    Treap
    luogu3369
    by sbn
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#define For(a,b,c)	for(int (a)=(b);(a)<(c);(a)++)
using namespace std;
struct	node{
    int u,v,s;//u是值,v是随机优先级,s是节点个数 
    node *ch[2];	//两个子树 
    int cmp(int x)	const{	//确定x与结点值的大小关系 
        if (x==u)	return -1;
        return	x < u ? 0:1;
    }
    void maintain(){	//维护结点个数 
        s=1;
        if (ch[0]!=NULL) s+=ch[0]->s;
        if (ch[1]!=NULL) s+=ch[1]->s;
    }
    node(int x)	:u(x){	//结点构造函数用于方便初始化 
        ch[0]=ch[1]=NULL;
        v=rand();//随机值 
        s=1; // 节点数初始化为1 
    }
} *T;
int n;
void rotate(node* &o,int d){	//旋转,0代表左旋,1代表右旋 
    node* k=o->ch[1^d];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    o->maintain();
    k->maintain();//一定要先维护o的节点数再维护k,因为o被转到k下面 
    o=k;
}
void insert(node* &o,int x){	//插入某个数 
    if (o==NULL)o=new node(x);	//建立结点 
    else{
        int d;
        if (x>=o->u)	d=1;	
        else d=0;				//不用maintain是因为插入重复值 
        insert(o->ch[d],x);		//递归插入 
        if (o->ch[d]->v > o->v)	rotate(o,d^1);	//如果子树优先级比根更大,则旋转 
    }											//1^d <=> 1-d但更快	
    o->maintain();
}
void remove(node* &o,int x){	//移除某个点 
    int d=o->cmp(x);			
    if (d==-1){					//如果o的值就是要移除的 
        node* k=o;
        if (o->ch[0]!=NULL&&o->ch[1]!=NULL){
            int d2=(o->ch[0]->v > o->ch[1]->v?1:0);	//如果左子树优先级大则右旋 
            rotate(o,d2);							//如果右子树优先级大则左旋 
            remove(o->ch[d2],x);					//继续删除 
        }else{							//如果o的左子树为空,右子树不为空,
            if (o->ch[0]==NULL)			// 则直接把指向o的点 指向o的右子树 
                o=o->ch[1];				// 反之左子树不为空,右子树为空 
            else
                o=o->ch[0];
            delete k; 
        }
    }else
        remove(o->ch[d],x);	//递归移除下面点 
    if (o!=NULL)	o->maintain(); 
}
int k_th(node* o,int x){	//查找第k大数 
    if (o==NULL||x<=0||x > o->s)	return 0;	
    int d=(o->ch[0]==NULL?0:o->ch[0]->s);	//d是左子树节点个数 
    if (x==d+1)	return o->u;				// 如果o正好是第k大个数 
    else
    if (x<=d)	return k_th(o->ch[0],x);	//如果第k大数在左子树 
    else
    return k_th(o->ch[1],x-d-1);		//如果第k大数在右子树 
}
int rank(node* o,int x){	//查询数(x的排名-1) 注意,x的排名应该在返回值基础上加1 
    if (o==NULL)	return 0;
    int d=(o->ch[0]==NULL?0:o->ch[0]->s);	//d是左子树结点个数 
    if (x<=o->u)	return rank(o->ch[0],x);//如果x在左子树 
    else return rank(o->ch[1],x)+d+1;	//如果x在右子树 
}
int pre(node* o,int x){	//求x的前驱 
	if (o==NULL)	return -2e9;
	int d=o->cmp(x);
	if (d<=0)return pre(o->ch[0],x);	//在左子树 考虑重复,所以d==-1时进左子树 
	return max(o->u,pre(o->ch[1],x));	 //在右子树 
} 
int suf(node* o,int x){//求x后继,同上 
	if (o==NULL)	return 2e9;
	int d=o->cmp(x);
	if (d==-1||d==1)	return suf(o->ch[1],x);
	return min(o->u,suf(o->ch[0],x));
}
void init(){
    srand(8921378);
    scanf("%d",&n);
    int a,f;
    scanf("%d%d",&f,&a);
    T=new node(a);
    For(i,1,n){
        scanf("%d",&f);	
        scanf("%d",&a);
        if (f==1)	insert(T,a);
        if (f==2)	remove(T,a);
        if (f==3)	printf("%d\n",rank(T,a)+1);
		if (f==4)	printf("%d\n",k_th(T,a));
    	if (f==5)	printf("%d\n",pre(T,a));
		if (f==6)	printf("%d\n",suf(T,a));
	}
}
int main(){
    init();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值