替罪羊树(模板)

传送门
替罪羊树,优秀的数据结构,关键思想是 假如这棵树长残了就拍扁重构成一棵二叉树,常数很小。alpha是一个平衡因子,用来判断这棵树是否长残,一般取0.5~0.9,比较玄学。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>

using namespace std;
const int MAXN = 100005;
const double alpha = 0.75;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

int memory[MAXN];   //内存池 
int cur[MAXN],m;  //拍扁的时候用的内存空间 
int rt,pool,poi,cnt,to_rebuild;
int ch[MAXN][2],val[MAXN],siz[MAXN],tot[MAXN];  //siz表示现存的子节点,tot表示总共的 
bool exist[MAXN];

inline bool isbad(int x){
    if((double)siz[x]*alpha<=(double)max(siz[ch[x][0]],siz[ch[x][1]])) return true;
    return false;
}

void dfs(int x){
    if(!x) return;dfs(ch[x][0]);
    if(exist[x]) cur[++poi]=x;
    else memory[++pool]=x;
    dfs(ch[x][1]);
}

void build(int &x,int l,int r){
    int mid=l+r>>1;
    x=cur[mid];
    if(l==r) {
        ch[x][0]=ch[x][1]=0;
        siz[x]=tot[x]=1;
        return;
    }
    if(l<mid) build(ch[x][0],l,mid-1);
    else ch[x][0]=0;
    build(ch[x][1],mid+1,r);
    tot[x]=tot[ch[x][0]]+tot[ch[x][1]]+1;
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}

inline void rebuild(int &x){
    poi=0;dfs(x);
    if(poi) build(x,1,poi);
    else x=0;
}

void Insert(int &now,int x){
    if(!now) {
        now=memory[pool--];val[now]=x;
        exist[now]=tot[now]=siz[now]=1;
        ch[now][0]=ch[now][1]=0;
        return ;
    } 
    tot[now]++,siz[now]++;
    if(val[now]>=x) Insert(ch[now][0],x);
    else Insert(ch[now][1],x);
    bool bad=isbad(now);
    if(!bad && to_rebuild){
        if(ch[now][0]==to_rebuild) rebuild(ch[now][0]);
        else rebuild(ch[now][1]);
        to_rebuild=0;
    }
    else if(bad) to_rebuild=now; 
}

int rk(int x){
    int now=rt,ret=1;
    while(now){
        if(val[now]>=x) now=ch[now][0];
        else {
            ret+=siz[ch[now][0]]+exist[now];
            now=ch[now][1];
        }
    }
    return ret;
}

int kth(int x){
    int now=rt;
    while(now){
        if(exist[now] && siz[ch[now][0]]+1==x)  return val[now];
        else if(siz[ch[now][0]]>=x) now=ch[now][0];
        else x-=siz[ch[now][0]]+exist[now],now=ch[now][1]; 
    }   
}

void Erase_pos(int &now,int x){
    if(exist[now] && siz[ch[now][0]]+1==x){
        exist[now]=0;siz[now]--;
        return;
    }
    siz[now]--;
    if(siz[ch[now][0]]+exist[now]>=x) Erase_pos(ch[now][0],x);
    else Erase_pos(ch[now][1],x-siz[ch[now][0]]-exist[now]);
}

void Erase_val(int x){
    Erase_pos(rt,rk(x));
    if((double)tot[rt]*alpha>siz[rt]) rebuild(rt);
}

int main(){
    for(int i=100000;i;i--) memory[++pool]=i;
    m=rd();int opt,x;
    while(m--){
        opt=rd(),x=rd();
        if(opt==1) {Insert(rt,x);if(isbad(rt)) rebuild(rt);}
        if(opt==2) Erase_val(x);
        if(opt==3) printf("%d
",rk(x));
        if(opt==4) printf("%d
",kth(x));
        if(opt==5) printf("%d
",kth(rk(x)-1));
        if(opt==6) printf("%d
",kth(rk(x+1)));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/9676837.html