【模板】替罪羊树

同【普通平衡树】

  • 替罪羊树单次操作的均摊复杂度为 \(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;
}
posted @ 2019-02-16 14:45  shellpicker  阅读(127)  评论(0编辑  收藏  举报