P3369 【模板】普通平衡树

splay

splay与他的解析

二叉搜索树

我们搞一棵树,保证左子树所有点的权值比父亲小,右子树所有点权值比父亲大

显然这个玩意可以快速查询一个数存不存在,排名啦啥的

插入的时候直接顺序造节点,删除的时候,断开重连是件很愚蠢的事情

应该把删除节点和他右子树最左边那个或者左子树最右边那个交换,销毁它

这样有什么问题呢?

如果坑逼出题人给你搞成了链,直接起飞成$ O(n)$了

这不就挂了

那么该怎么搞呢

伸展树splay出现了

splay,旋转,自我调整,

旋转

捕获.PNG

本图片引用自liuzhangfeiabc课件

我们可以看到,转x,就是让f变成x的右儿子,x的右儿子变成f的左儿子,x的右儿子变成f,x代替f

void ro(int x){
    int f=po[x].fa;
    int gf=po[f].fa;
    int xp=ident(x);
    int fp=ident(f);
    connect(po[x].son[xp^1],f,xp);
    connect(f,x,xp^1);
    connect(x,gf,fp);
    update(f);
    update(x);
}

但是出题人还能接着卡你

怎么办呢,我们一次转俩,直接强行链改树

splay

void splay(int x,int to){
    to=po[to].fa;
    while(po[x].fa!=to){
        int f=po[x].fa;
        if(po[f].fa==to) ro(x);
        else if(ident(x)==ident(f)) ro(f),ro(x);
        else ro(x),ro(x);
    }
}.

这又是在干什么呢

我们可以把一个节点移到你想去的任何位置如果爹,爹的爹和儿子共线,就要先转爹,不然就转两次儿子,就可以成功的压成树了

更具体的操作

插入 这里没什么大坑,就是记得最后splay一下

void insert(int x){
    int now=po[0].son[1];
    if(now==0){
        creat(x,0);
        po[0].son[1]=tot;
    }else{
        while(1){
            po[now].sum++;
            if(po[now].val==x){
                po[now].cnt++;
                splay(now,po[0].son[1]);
                return ;
            }
            int nex=x<po[now].val?0:1;
            if(!po[now].son[nex]){
                int p=creat(x,now);
                po[now].son[nex]=p;
                splay(p,po[0].son[1]);
                return ;
            }
            now=po[now].son[nex];
        }
    }
}

寻找排名

也很好理解,记得splay

int find(int x){
    int now=po[0].son[1];
    while(1){
        if(!now) return 0;
        if(po[now].val==x) {
            splay(now,po[0].son[1]);
            return now;
        }
        int nex=x<po[now].val?0:1;
        now=po[now].son[nex];
    }
}

删除

还是很好解决的,先找到它,如果它是叶子,直接删掉,如果它没有左儿子的,就直接把右儿子接上去,如果都有,就找它右子树最左的那个,splay进行交换,销毁

void del(int x){
    int pos=find(x);
    if(!pos) return ;
    if(po[pos].cnt>1){
        po[pos].cnt--;
        po[pos].sum--;
        return ;
    }else{
        if(!po[pos].son[0]&&!po[pos].son[1]) {
            po[0].son[1]=0;
            return ;
        }else if(!po[pos].son[0]){
            po[0].son[1]=po[pos].son[1];
            po[po[0].son[1]].fa=0;
            return ;
        } else{
            int le=po[pos].son[0];
            while(po[le].son[1]) le=po[le].son[1];
            splay(le,po[pos].son[0]);
            connect(po[pos].son[1],le,1);
            connect(le,0,1);
            update(le);
        }
    }
}

按照排名找数

同理

找前缀

记得一直取max

后缀

和前缀反着

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstring>
#define int long long
using namespace std;
const int maxn=1e6+10;
const int mod=10007;
const int inf=1e9+10;
struct p{
    int fa;
    int son[2];
    int val;
    int cnt;
    int sum;
}po[maxn];
int tot;
int n,opt;int x;
int ps;
inline int read(){
    int res=0,k=1;
    char c=getchar();
    while(!isdigit(c)){
        if(c=='-')k=-1;
        c=getchar();
    }
    while(isdigit(c)){
        res=(res<<1)+(res<<3)+c-48;
        c=getchar();
    }
    return res*k;
}
void update(int x){
    po[x].sum=po[po[x].son[0]].sum+po[po[x].son[1]].sum+po[x].cnt;
}
int ident(int x){
    return po[po[x].fa].son[0]==x?0:1;
}
void connect(int x,int fa,int s){
    po[fa].son[s]=x;
    po[x].fa=fa;
}
void ro(int x){
    int f=po[x].fa;
    int gf=po[f].fa;
    int xp=ident(x);
    int fp=ident(f);
    connect(po[x].son[xp^1],f,xp);
    connect(f,x,xp^1);
    connect(x,gf,fp);
    update(f);
    update(x);
}
void splay(int x,int to){
    to=po[to].fa;
    while(po[x].fa!=to){
        int f=po[x].fa;
        if(po[f].fa==to) ro(x);
        else if(ident(x)==ident(f)) ro(f),ro(x);
        else ro(x),ro(x);
    }
}
int creat(int val,int f){
    ++tot;
    po[tot].fa=f;
    po[tot].sum=po[tot].cnt=1;
    po[tot].val=val;
    return tot;
}
void insert(int x){
    int now=po[0].son[1];
    if(now==0){
        creat(x,0);
        po[0].son[1]=tot;
    }else{
        while(1){
            po[now].sum++;
            if(po[now].val==x){
                po[now].cnt++;
                splay(now,po[0].son[1]);
                return ;
            }
            int nex=x<po[now].val?0:1;
            if(!po[now].son[nex]){
                int p=creat(x,now);
                po[now].son[nex]=p;
                splay(p,po[0].son[1]);
                return ;
            }
            now=po[now].son[nex];
        }
    }
}
int find(int x){
    int now=po[0].son[1];
    while(1){
        if(!now) return 0;
        if(po[now].val==x) {
            splay(now,po[0].son[1]);
            return now;
        }
        int nex=x<po[now].val?0:1;
        now=po[now].son[nex];
    }
}
void del(int x){
    int pos=find(x);
    if(!pos) return ;
    if(po[pos].cnt>1){
        po[pos].cnt--;
        po[pos].sum--;
        return ;
    }else{
        if(!po[pos].son[0]&&!po[pos].son[1]) {
            po[0].son[1]=0;
            return ;
        }else if(!po[pos].son[0]){
            po[0].son[1]=po[pos].son[1];
            po[po[0].son[1]].fa=0;
            return ;
        } else{
            int le=po[pos].son[0];
            while(po[le].son[1]) le=po[le].son[1];
            splay(le,po[pos].son[0]);
            connect(po[pos].son[1],le,1);
            connect(le,0,1);
            update(le);
        }
    }
}
int rak(int x){
    int now=po[0].son[1];
    int ans=0;
    while(1){
        if(po[now].val==x) {
    //  splay(now,po[0].son[1]);
         ans+=po[po[now].son[0]].sum+1;
         splay(now,po[0].son[1]);;
         return ans;
        }
        int nex=x<po[now].val?0:1;
        if(nex==1) ans =ans+po[po[now].son[0]].sum+po[now].cnt;
        now=po[now].son[nex];
    }
}
int kth(int x){
    int now=po[0].son[1];
    while(1){
        int re=po[now].sum-po[po[now].son[1]].sum;
        if(po[po[now].son[0]].sum<x&&x<=re){
            return po[now].val;
        }
        if(x<re) now=po[now].son[0];
        else now =po[now].son[1],x-=re;
    }
}
int lower(int x){
    int now=po[0].son[1];
    int ans=-inf;
    while(now){
        if(po[now].val<x) ans=max(ans,po[now].val);
        int nex=x<=po[now].val?0:1;//等于也要往左走 
        now=po[now].son[nex];
    }
    return ans;
}
int upper(int x){
    int now=po[0].son[1];
    int ans=inf;
    while(now){
        if(po[now].val>x) ans=min(ans,po[now].val);
        int nex=x<po[now].val?0:1;
        now=po[now].son[nex];
    }
    return ans;
}
signed main(){
    n=read();
    while(n--){
        opt=read();
        x=read();
        if(opt==1) insert(x);
        else if(opt==2) del(x);
        else if(opt==3) printf("%dn",rak(x));
        else if(opt==4) printf("%dn",kth(x));
        else if(opt==5) printf("%dn",lower(x));
        else if(opt==6) printf("%dn",upper(x));
    }
    return 0;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇