/*
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;
}
【Treap模板】【指针】【luogu3369】
最新推荐文章于 2020-09-09 15:40:25 发布