【模板】替罪羊树
同【普通平衡树】
- 替罪羊树单次操作的均摊复杂度为 \(O(logn)\)。
- 由于替罪羊树的删除方式为懒惰删除,因此在查询第 K 大和查排名时必须考虑子树实际的大小。
- 由于懒惰删除的效果,Treap 式的前驱后继查询方式对替罪羊树并不适用,需要换成查排名或求第 K 大的方式处理。
代码如下
/*All the functions are recursive.*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const double alpha=0.7;
struct node{
#define ls(x) t[x].lc
#define rs(x) t[x].rc
int lc,rc,val,size,sum,cnt;
}t[maxn];
int tot,root;
inline int newnode(int val){
++tot,t[tot].val=val,t[tot].cnt=t[tot].sum=t[tot].size=1;
return tot;
}
inline bool isbad(int x){
return (double)max(t[ls(x)].sum,t[rs(x)].sum)>t[x].sum*alpha;
}
inline void pushup(int x){
t[x].size=t[ls(x)].size+t[rs(x)].size+t[x].cnt;
t[x].sum=t[ls(x)].sum+t[rs(x)].sum+t[x].cnt;
}
inline void dfs(int x,vector<int> &v){
if(ls(x))dfs(ls(x),v);
if(t[x].cnt)v.push_back(x);
if(rs(x))dfs(rs(x),v);
}
inline int build(int l,int r,vector<int> &v){
if(l>r)return 0;
int mid=l+r>>1;
int x=v[mid];
ls(x)=build(l,mid-1,v),rs(x)=build(mid+1,r,v);
pushup(x);
return x;
}
inline void rebuild(int &x){
vector<int> v;
dfs(x,v);
x=build(0,v.size()-1,v);
}
void insert(int &x,int val){
if(!x)x=newnode(val);
else if(val==t[x].val)++t[x].cnt;
else if(val<t[x].val)insert(ls(x),val);
else insert(rs(x),val);
pushup(x);
if(isbad(x))rebuild(x);
}
void remove(int &x,int val){
if(!x)return;
else if(t[x].val==val)--t[x].cnt;
else if(val<t[x].val)remove(ls(x),val);
else remove(rs(x),val);
pushup(x);
if(isbad(x))rebuild(x);
}
int kth(int x,int k){//cmp with size -> we can ignore the remove tag
if(k<=t[ls(x)].size)return kth(ls(x),k);
else if(k>t[ls(x)].size+t[x].cnt)return kth(rs(x),k-t[ls(x)].size-t[x].cnt);
else return t[x].val;
}
int getrank(int x,int val){//cmp with size -> we can ignore the remove tag
if(val==t[x].val)return t[ls(x)].size+1;
else if(val<t[x].val)return getrank(ls(x),val);
else return getrank(rs(x),val)+t[ls(x)].size+t[x].cnt;
}
int upper(int x,int val){
if(!x)return 1;
else if(t[x].cnt&&val==t[x].val)return t[x].cnt+t[ls(x)].size+1;
else if(val<t[x].val)return upper(ls(x),val);
else return t[x].cnt+t[ls(x)].size+upper(rs(x),val);
}
int lower(int x,int val){
if(!x)return 0;
else if(t[x].cnt&&val==t[x].val)return t[ls(x)].size;
else if(val<t[x].val)return lower(ls(x),val);
else return t[x].cnt+t[ls(x)].size+lower(rs(x),val);
}
int main(){
int n;scanf("%d",&n);
while(n--){
int opt,val;scanf("%d%d",&opt,&val);
if(opt==1)insert(root,val);
else if(opt==2)remove(root,val);
else if(opt==3)printf("%d\n",getrank(root,val));
else if(opt==4)printf("%d\n",kth(root,val));
else if(opt==5)printf("%d\n",kth(root,lower(root,val)));
else if(opt==6)printf("%d\n",kth(root,upper(root,val)));
}
return 0;
}