[luogu3369]普通平衡树(替罪羊树模板)
解题关键:由于需要根据平衡进行重建,所以不能进行去重,否则无法保证平衡性。
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> #include<vector> using namespace std; typedef long long ll; const double alpha=0.7; const int N=1e5+500; int n; namespace ScapegoatTree{ struct node{ int l,r,v,sz,valid; bool del; }t[N<<2]; int tot=0,rt=0; #define ls(o) t[o].l #define rs(o) t[o].r #define pb push_back int new_node(int x){++tot;t[tot].l=t[tot].r=0;t[tot].v=x;t[tot].sz=t[tot].valid=1;t[tot].del=0;return tot;} bool Bad(int o){ return (double)t[ls(o)].sz>alpha*t[o].sz||(double)t[rs(o)].sz>alpha*t[o].sz; } void Updata(int o){ t[o].sz=t[ls(o)].sz+t[rs(o)].sz+1; t[o].valid=t[ls(o)].valid+t[rs(o)].valid+!t[o].del; } void Dfs(int o,std::vector<int> &v){ if(!o) return; Dfs(ls(o),v); if(!t[o].del) v.pb(o); Dfs(rs(o),v); } int Build(std::vector<int> &v,int l,int r){ if(l>r) return 0;//原因是右边界不包含 int mid=(l+r)>>1,o=v[mid]; ls(o)=Build(v,l,mid-1); rs(o)=Build(v,mid+1,r); Updata(o); return o; } void ReBuild(int &o){ std::vector<int>v; Dfs(o,v); o=Build(v,0,(int)v.size()-1); } void Insert(int x,int &o){ if(!o){ o=new_node(x); return ; } if(x>=t[o].v) Insert(x,rs(o)); else Insert(x,ls(o)); Updata(o); if(Bad(o)) ReBuild(o); return; } //del with rnk void Delete(int o,int Rnk){ if(!t[o].del&&Rnk==t[ls(o)].valid+1) { t[o].del=1; --t[o].valid; return; } if(Rnk<=t[ls(o)].valid+!t[o].del) Delete(ls(o),Rnk); else Delete(rs(o),Rnk-t[ls(o)].valid-!t[o].del); Updata(o); } int GetRank(int o,int x){ int ans=1; while(o){ if(t[o].v>=x) o=ls(o); else{ ans+=t[ls(o)].valid+!t[o].del; o=rs(o); } } return ans; } int FindKth(int o,int x) { while(o){ if(!t[o].del&&t[ls(o)].valid+1==x) {return t[o].v;} if(t[ls(o)].valid>=x) o=ls(o); else { x-=t[ls(o)].valid+!t[o].del; o=rs(o); } } } int GetPred(int o,int x){ return FindKth(o,GetRank(o,x)-1); } int GetSucc(int o,int x){ return FindKth(o,GetRank(o,x+1)); } } using namespace ScapegoatTree; int main() { scanf("%d",&n); rt=0; while(n--) { int op,x; scanf("%d%d",&op,&x); if(op==1) Insert(x,rt); if(op==2) Delete(rt,GetRank(rt,x)); if(op==3) printf("%d\n",GetRank(rt,x)); if(op==4) printf("%d\n",FindKth(rt,x)); if(op==5) printf("%d\n",GetPred(rt,x)); if(op==6) printf("%d\n",GetSucc(rt,x)); } return 0; }