• [总结] 替罪羊树学习笔记


    突然不会写学习笔记了...

    反正是给自己看的

    那就想到哪写到哪吧

    思想

    不基于旋转而基于暴力重构的平衡树

    采用懒惰删除法 每次删除只打标记,在重构时统一删除

    如果某个点的子树过于不平衡或删除了过多的元素 那就需要进行重构

    重构时暴力dfs整棵子树,碰见打了删除标记的节点就扔进内存池,否则按照中序遍历存下来,然后递归建满二叉树即可。

    代码长这样:

    void dfs(int &len,int x){
        if(!x) return;
        dfs(len,ls);
        if(!del[x]) cz[++len]=x;
        else dp[++dc]=x;
        dfs(len,rs);
    }
    
    int build(int l,int r){
        if(l>r) return 0;
        int mid=l+r>>1;
        int x=cz[mid];sze[x]=1;cnt[x]=1;ls=rs=0;del[x]=0;
        if(l==r) return x;
        ls=build(l,mid-1),rs=build(mid+1,r);
        if(ls) fa[ls]=x;
        if(rs) fa[rs]=x;
        pushup(x); return x;
    }
    
    void pia(int x){
        int f=fa[x],len=0;
        dfs(len,x);
        int t=build(1,len);
        if(root==x) root=t;
        else ch[f][ch[f][1]==x]=t,fa[t]=f;
    }
    

    一定要注意及时更新信息

    普通平衡树的代码:

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using std::min;
    using std::max;
    using std::swap;
    using std::vector;
    typedef double db;
    typedef long long ll;
    #define pb(A) push_back(A)
    #define pii std::pair<int,int>
    #define all(A) A.begin(),A.end()
    #define mp(A,B) std::make_pair(A,B)
    const int N=1e6+5;
    const db alph=0.75;
    #define ls ch[x][0]
    #define rs ch[x][1]
    
    int n,tot,dp[N],dc,cz[N];
    int sze[N],ch[N][2],cnt[N];
    int val[N],root,del[N],fa[N];
    
    int newnode(){
        int t=dc?dp[dc--]:++tot;
        fa[t]=cnt[t]=sze[t]=val[t]=ch[t][0]=ch[t][1]=del[t]=0;
        return t;
    }
    
    bool chk(int x){
        return alph*sze[x]<=max(sze[ls],sze[rs]) or alph*cnt[x]>sze[x];
    }
    
    void dfs(int &len,int x){
        if(!x) return;
        dfs(len,ls);
        if(!del[x]) cz[++len]=x;
        else dp[++dc]=x;
        dfs(len,rs);
    }
    
    void pushup(int x){
        cnt[x]=cnt[ls]+cnt[rs]+1;
        sze[x]=sze[ls]+sze[rs]+!del[x];
    }
    
    int build(int l,int r){
        if(l>r) return 0;
        int mid=l+r>>1;
        int x=cz[mid];sze[x]=1;cnt[x]=1;ls=rs=0;del[x]=0;
        if(l==r) return x;
        ls=build(l,mid-1),rs=build(mid+1,r);
        if(ls) fa[ls]=x;
        if(rs) fa[rs]=x;
        pushup(x); return x;
    }
    
    void pia(int x){
        int f=fa[x],len=0;
        dfs(len,x);
        int t=build(1,len);
        if(root==x) root=t;
        else ch[f][ch[f][1]==x]=t,fa[t]=f;
    }
    
    int ins(int x,int v,int f,int &flag){
        if(!x){
            x=newnode();
            cnt[x]=sze[x]=1,val[x]=v,fa[x]=f;
            return x;
        } int d=val[x]<v;
        sze[x]++;cnt[x]++;
        ch[x][d]=ins(ch[x][d],v,x,flag);
        if(chk(x)) flag=x;
        return x;
    }
    
    void erase(int x,int rk,int &flag){
        if(!del[x] and sze[ls]+1==rk){
            del[x]=1;sze[x]--;
            return;
        } sze[x]--;
        if(sze[ls]>=rk) erase(ls,rk,flag);
        else erase(rs,rk-sze[ls]-!del[x],flag);
        if(chk(x)) flag=x;
    }
    
    int kth(int x,int k){
        if(!del[x]){
            if(sze[ls]==k-1) return val[x];
            if(sze[ls]>=k) return kth(ls,k);
            return kth(rs,k-sze[ls]-1);
        } else{
            if(sze[ls]>=k) return kth(ls,k);
            else return kth(rs,k-sze[ls]);
        }
    }
    
    int find(int x,int k){
        if(!x) return 0;
        if(val[x]>=k) return find(ls,k);
        else return find(rs,k)+sze[ls]+!del[x];
    }
    
    int getint(){
        int X=0,w=0;char ch=getchar();
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }
    
    signed main(){
        n=getint();
        while(n--){
            int opt=getint(),x=getint();
            if(opt==1 or opt==2){
                int flag=0;
                if(opt==1) root=ins(root,x,0,flag);
                else erase(root,find(root,x)+1,flag);
                if(flag) pia(flag);
            }
            if(opt==3) printf("%d
    ",find(root,x)+1);
            if(opt==4) printf("%d
    ",kth(root,x));
            if(opt==5) printf("%d
    ",kth(root,find(root,x)));
            if(opt==6) printf("%d
    ",kth(root,find(root,x+1)+1));
        } return 0;
    }
    

    突然想到了一种不用记录fa的方法哈哈哈哈哈!!!
    我们需要记录fa的本质原因是因为在重构的时候要更改fa的ch数组

    既然这样我们传参的时候传一个pair包括x和fa[x]不就好了!

    哈哈哈哈哈我真是个小机灵鬼

  • 相关阅读:
    Log4j详细介绍(五)----输出地Appender
    Java抽象类与接口的区别
    深入理解Java的接口和抽象类
    小程序
    小程序
    小程序
    CMS
    CMS
    微信小程序
    微信小程序
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/10300671.html
Copyright © 2020-2023  润新知