P3369-[模板]普通平衡樹【替罪羊樹】
阿新 • • 發佈:2019-01-05
正題
評測記錄:https://www.luogu.org/recordnew/lists?uid=SSL_WYC_zombieeeeee&pid=P3369&status=&sort=0
題目大意
要求支援查詢一個數字的排名,查詢該排名的數字,插入數字,刪除數字,求前驅後繼。
解題思路
替罪羊樹
#include<cstdio>
#include<algorithm>
#include<cctype>
#define alpha 0.8
#define N 100010
using namespace std;
inline int read(){
int x(0),sign(0);
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') sign=1;
ch= getchar();
}
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return sign?-x:x;
}
struct goat_Tree{
int l[N],r[N],size[N],val[N],valid[N],total[N];
int cur[N],memory[N];
bool exist[N];
int root,poi,pool,cnt;
void ReMemory(){
for(int i=N-10;i>=1;i--)
memory[ ++pool]=i;
}
bool Isbad(int now){
if((double)valid[now]*alpha<=(double)max(valid[l[now]],valid[r[now]]))
return true;
else return false;
}
void Beat(int now){
if(!now) return;
Beat(l[now]);
if(exist[now]) cur[++poi]=now;
else memory[++pool]=now;
Beat(r[now]);
}
void New(int x){
l[x]=r[x]=0;
total[x]=valid[x]=1;
}
void Build(int ls,int rs,int &now){
int mid=(ls+rs)>>1;
now=cur[mid];
if(ls==rs){
New(now);
return;
}
if(ls<mid) Build(ls,mid-1,l[now]);
else l[now]=0;
Build(mid+1,rs,r[now]);
total[now]=total[l[now]]+total[r[now]]+1;
valid[now]=valid[l[now]]+valid[r[now]]+1;
}
void ReBuild(int &now){
poi=0;Beat(now);
if(poi) Build(1,poi,now);
else now=0;
}
int GetRankByVal(int k){
int now=root;
int ans=1;
while(now){
if(val[now]>=k) now=l[now];
else{
ans+=valid[l[now]]+exist[now];
now=r[now];
}
}
return ans;
}
int GetValByRank(int k){
int now=root;
while(now){
if(exist[now]&&valid[l[now]]+1==k)
return val[now];
if(valid[l[now]]>=k) now=l[now];
else{
k-=valid[l[now]]+exist[now];
now=r[now];
}
}
}
void Insert(int &now,int num){
if(!now){
now=memory[pool--];val[now]=num;
New(now);exist[now]=1;
return;
}
total[now]++;valid[now]++;
if(val[now]>=num) Insert(l[now],num);
else Insert(r[now],num);
if(Isbad(now))
ReBuild(now);
}
void Remove_z(int &now,int tar){
if(exist[now]&&valid[l[now]]+1==tar){
exist[now]=0;valid[now]--;
return;
}
valid[now]--;
if(valid[l[now]]+exist[now]>=tar)
Remove_z(l[now],tar);
else Remove_z(r[now],tar-valid[l[now]]-exist[now]);
}
void Remove(int tar){
Remove_z(root,GetRankByVal(tar));
if((double)total[root]*alpha>valid[root])
ReBuild(root);
}
}a;
int main()
{
int opt,x,m;
a.ReMemory();
scanf("%d",&m);
while(m--)
{
opt=read();x=read();
if(opt==1) a.Insert(a.root,x);
if(opt==2) a.Remove(x);
if(opt==3) printf("%d\n",a.GetRankByVal(x));
if(opt==4) printf("%d\n",a.GetValByRank(x));
if(opt==5) printf("%d\n",a.GetValByRank(a.GetRankByVal(x)-1));
if(opt==6) printf("%d\n",a.GetValByRank(a.GetRankByVal(x+1)));
}
}