平衡树 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;
}