新建结点
int cnt,root;
inline int newnode(int val){
fhq[++cnt].val=val;
fhq[cnt].key=rand();
fhq[cnt].size=1;
return cnt;
}
按权分裂
void split(int now,int val,int &x,int &y){
if(!now)x=y=0;
else {
if(fhq[now].val<=val){//小于等于val给左边(x),大于val给右边(y)
x=now;
split(fhq[now].r,val,fhq[now].r,y);
}else {
y=now;
split(fhq[now].l,val,x,fhq[now].l);
}
update(now);
}
}
按大小分裂
void split(int now,int sz,int &x,int &y){
if(!now)x=y=0;
else {
if(fhq[now].tag)pushdown(now);
if(fhq[ls].size<sz){// 小于size给左边(x),大于等于size给右边(y)
x=now;
split(rs,sz-fhq[ls].size-1,rs,y);
}else {
y=now;
split(ls,sz,x,ls);
}
pushup(now);
}
}
合并
int merge(int x,int y){//保证x子树比y子树的值小
if(!x||!y)return x+y;
if(fhq[x].key>fhq[y].key){//x的索引大于y的
fhq[x].r=merge(fhq[x].r,y);
//满足二叉堆和搜索数的性质,y子树在x子树的右下方
update(x);return x;
}else {//反之则反过来
fhq[y].l=merge(x,fhq[y].l);
update(y);return y;
}
}
插入
inline void ins(int val,int x,int y){
split(root,val,x,y);//按值分裂
root=merge(merge(x,newnode(val)),y);//合并x,val,y三棵子树
}
删除
inline void del(int val,int x,int y,int z){
split(root,val,x,z);//按val将整棵树分裂成x和z两棵子树
split(x,val-1,x,y);//按val-1将x树分裂成x,y两棵子树
//此时,y数上的点一定等于val
y=merge(fhq[y].l,fhq[y].r);//删除掉根就好啦
root=merge(merge(x,y),z);//将x,y,z合并
}
查 rank
inline void rank(int val,int x,int y){//查询值的排名
split(root,val-1,x,y);//按照val-1分裂
printf("%d\n",fhq[x].size+1);
//此时x子树的值一定小于等于val-1,则其大小+1即为val的排名
root=merge(x,y);//再合并回来!
}
前驱后继
inline void pre(int val,int x,int y){
split(root,val-1,x,y);//按val-1分裂,则x子树的最右边即为前驱(x<=val-1)
int now=x;
while(fhq[now].r)now=fhq[now].r;
printf("%d\n",fhq[now].val);
root=merge(x,y);
}
inline void nxt(int val,int x,int y){
split(root,val,x,y);//按val分裂,则y子树的最左边即为后继(y>val)
int now=y;
while(fhq[now].l)now=fhq[now].l;
printf("%d\n",fhq[now].val);
root=merge(x,y);
}