其他分享
首页 > 其他分享> > [学习笔记]替罪羊树

[学习笔记]替罪羊树

作者:互联网

替罪羊树——简单粗暴的数据结构 - a_forever_dream的..._CSDN博客

一种简单粗暴的数据结构(我自认为暴力“不优雅”。。。)

和其他“优雅”的splay,fhq-treap不同

替罪羊既不旋转,也不分裂合并

我看谁不顺眼,直接让其暴力重构!

 

思路就是这样。

特点是:

1.如果一个点的左子树或者右子树的节点个数>x的节点个数*alpha(0.5~1.0之间的一个值),那么暴力重构整个子树

2.懒惰删除,因为SGT不够灵活。对删除的点打上标记,并且在祖先节点更新信息。但是不删掉节点本身(名存实亡)。

3.如果一个点子树的已经删除部分占30%左右,暴力重构子树

所以,一个点的信息是:

sz:子树节点个数

cnt:子树实际存在的节点个数

val:自己的权值

ch[2]:两个儿子

die:是否被删除

 

先说暴力重构:

分三步:

1.dfs(x),把x子树所有没有删除的点加入一个数组里

2.build(l,r),分治建树

3.pushup(fa[x])把x的father的信息更新一下(node中可以不记录father,临时记录即可)

 

操作:

(最大的坑莫过于未考虑到名存实亡的点)

insert:类比splay,while循环,找到位置之后加入节点(可以同一个值分成不同的点,x和左右子树的关系变成不严格的即可)

    最后从上而下尝试rebuild

dele:找到后die=1,

    注意:必须找到一个没有被删除的。所以,不用权值找,而用第k大(坑了2h)

    (权值的话,如果x被删除了你不知道往哪里走)

    最后从上而下尝试rebuild

rank,kth,pre,bac都差不多,kth的返回,注意当前点必须是未删除点

 

复杂度:alpha调好,可以保证O(nlogn)(alpha一般是0.75)

 

代码:

P3369 【模板】普通平衡树 

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=100000+5;
const double al=0.75;
struct node{
    int ch[2],val;
    int sz,cnt;
    bool die;
    void init(int v){
        sz=1;cnt=1;val=v;ch[0]=0;ch[1]=0;
    }
}t[N];
void pushup(int x){
    if(!x) return;
    t[x].sz=t[t[x].ch[0]].sz+t[t[x].ch[1]].sz+1;
    t[x].cnt=t[t[x].ch[0]].cnt+t[t[x].ch[1]].cnt+(!t[x].die);
}
int rt;
int tot=0;
int q[N],num;
int isbad(int x){
    return (t[t[x].ch[0]].sz>t[x].sz*al||t[t[x].ch[1]].sz>t[x].sz*al||t[x].cnt<t[x].sz*al);
}
void dfs(int x){
    if(!x) return ;
    dfs(t[x].ch[0]);
    if(!t[x].die) {
        q[++num]=x;
    //    cout<<t[x].val<<" ";
    }
    dfs(t[x].ch[1]);
}
int build(int l,int r){//warning!! no consider fa
    if(l>r) return 0;
    int mid=(l+r)>>1;
    int x=q[mid];
//    t[x].fa=0;
    t[x].ch[0]=build(l,mid-1);
    t[x].ch[1]=build(mid+1,r);
//    t[t[x].ch[0]].fa=x;
//    t[t[x].ch[1]].fa=x;
    pushup(x);    
    return x;
}
void rebuild(int &x){
    //cout<<" rerererreuildbuilbublilbiulib "<<x<<endl;
//cout<<" xxx "<<x<<endl;
    num=0;
    //x=2;return;
    //int y=t[x].fa;
//    int d=t[y].ch[1]==x;
    dfs(x);
    //cout<<" num "<<num<<endl;;
//    for(reg i=1;i<=num;++i){
//        cout<<t[q[i]].val<<" ";
//    }cout<<endl;
    x=build(1,num);
//    cout<<" xx "<<x<<endl;
    pushup(x);
}
int sta[N],top;
void ins(int v){
    if(!rt){
        rt=++tot;
        t[rt].init(v);
        return;
    }
    int x=rt;
    top=0;
    while(1){
        int d=t[x].val<=v;
        ++t[x].sz;
        ++t[x].cnt;
        sta[++top]=x;
        if(!t[x].ch[d]){
            t[x].ch[d]=++tot;
            t[tot].init(v);
            break;
        }
        x=t[x].ch[d];
    }
    int las=0;
    for(reg i=1;i<=top;++i){
        if(isbad(sta[i])){
            if(las==0) {
            //    cout<<" rrt "<<endl,
                rebuild(rt);
            //    cout<<rt<<" val "<<t[rt].val<<endl;
            }
            else rebuild(t[las].ch[t[las].ch[1]==sta[i]]),pushup(las);
            return;
        }
        las=sta[i];
    }
}
void del(int k){
    int x=rt;
    top=0;
    while(1){
        int d=t[t[x].ch[0]].cnt+(!t[x].die);
        sta[++top]=x;
        --t[x].cnt;
        if(!t[x].die&&d==k) {
            t[x].die=1;
            break;
        }
        if(t[t[x].ch[0]].cnt>=k) x=t[x].ch[0];
        else{
            k-=d;x=t[x].ch[1];
        }
    }
    int las=0;
    for(reg i=1;i<=top;++i){
        if(isbad(sta[i])){
            if(las==0) rebuild(rt);
            else //cout<<" las "<<las<<endl,
            rebuild(t[las].ch[t[las].ch[1]==sta[i]]),pushup(las);
            return;
        }
        las=sta[i];
    }
}
int kth(int k){
    int x=rt;
    while(1){
    //    cout<<" xx "<<x<<" "<<t[x].val<<" "<<t[x].sz<<" "<<t[x].cnt<<endl;
        int d=t[t[x].ch[0]].cnt+(!t[x].die);
        if(!t[x].die&&d==k) return t[x].val;
        if(t[t[x].ch[0]].cnt>=k) x=t[x].ch[0];
        else{
            k-=d;x=t[x].ch[1];
        }
    }
    return -23333333;
}
int rk(int v){
    int x=rt;
    int ret=1;
    while(x){
        int d=t[x].val<v;
        if(d) ret+=t[t[x].ch[0]].cnt+(!t[x].die),x=t[x].ch[1];
        else x=t[x].ch[0];
    }
//cout<<" ret "<<ret<<endl;
    return ret;
}
int n;
int main(){
    rd(n);
    int op,x;
    for(reg i=1;i<=n;++i){
        rd(op);rd(x);
        if(op==1) ins(x);
        else if(op==2) del(rk(x));
        else if(op==3) printf("%d\n",rk(x));
        else if(op==4) printf("%d\n",kth(x));
        else if(op==5) printf("%d\n",kth(rk(x)-1));
        else printf("%d\n",kth(rk(x+1)));
    //    cout<<" rt "<<rt<<" "<<t[rt].val<<" :: "<<t[rt].sz<<" "<<t[rt].cnt<<endl;
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/2/5 19:28:58
*/

 

标签:sz,cnt,ch,int,替罪羊,笔记,学习,子树,节点
来源: https://www.cnblogs.com/Miracevin/p/10353237.html