zoukankan      html  css  js  c++  java
  • 替罪羊树(模板)

    传送门
    替罪羊树,优秀的数据结构,关键思想是 假如这棵树长残了就拍扁重构成一棵二叉树,常数很小。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;
    }
  • 相关阅读:
    HTML5服务器发送事件(Server-Send Events)
    无人问津的排序(一)----希尔排序
    NB二人组(二)----归并排序
    40、常用字符串格式化有哪几种?
    39、请用代码简答实现stack
    38、一行代码实现删除列表中重复的值 ?
    37、如何在函数中设置一个全局变量 ?
    NB二人组(一)----堆排序
    快排
    LOW逼三人组(三)----插入排序
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9676837.html
Copyright © 2011-2022 走看看