【模板篇】伸展树Splay Tree(此坑待填)

本文介绍了伸展树(Splay Tree)的概念及其如何通过旋转操作维持树的高度平衡,以达到高效查找的目的。同时提供了Splay Tree的C++实现代码,并展示了插入、删除等基本操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

已填坑: 请移步…
Splay?伸展。
Splay Tree?伸展树。
遇事不决问度娘。。
从前,有种东西叫BST(Binary Search Tree,二叉查找树),各位都听说过吧?
此BST能较为高效的查找数据。。(所以是查找树嘛)
而它却有一个致命的缺点!常常会被卡成一条链。。
不是链的时候树也会很高。。。。效率很难维持住O(nlogn)
所以,人们研究了各种的二叉平衡树,通过对BST各种姿势的调整维护树的左右平衡,使树高不会太高,从而防止效率退化。。
Splay是其中的一种(然而还是会被卡)。。在省选这个阶段似乎是够用了。。
Splay有很多操作,其中最重要的,当然是splay..
Splay在维护信息时,会将各种东西伸展到根上,
(扭来扭去的),这也就是splay树名字的由来了吧。。
先把板子丢上来…

#include <cstdio>

const int MAXQ=0x186AF;
const int INF=~0U>>2;

#define gc getchar()
#define xx(x) printf("%d\n",x)

inline int gnum(){
    int a=0;char c=gc;bool f=0;
    for(;(c<'0'||c>'9')&&c!='-';c=gc);
    if(c=='-') c=gc,f=1;
    for(;c>='0'&&c<='9';c=gc) a=(a<<1)+(a<<3)+c-'0';
    if(f) return -a; return a;
}

inline int max(const int &a,const int &b){
    if(a<b) return b; return a; 
}

inline int min(const int &a,const int &b){
    if(a<b) return a; return b;
}

struct SPLAY{
    int val,sz,cnt;
    SPLAY *fa,*ch[2];

    void update();
    int get_wh();
    void set_ch(int,SPLAY*);
}pool[MAXQ],*rt,*null;

void SPLAY::update(){
    sz=ch[0]->sz+ch[1]->sz+cnt;
} 

int SPLAY::get_wh(){
    return fa->ch[0]==this?0:1;
}

void SPLAY::set_ch(int wh,SPLAY *child){
    ch[wh]=child;
    if(child!=null) child->fa=this;
    update();
}

int tot=0;

inline SPLAY* NEW(int val){
    SPLAY *now=pool+ ++tot;
    now->val=val;
    now->sz=now->cnt=1;
    now->fa=now->ch[0]=now->ch[1]=null;
    return now;
} 

void init(){
    null=pool;
    null->val=null->sz=null->cnt=0;
    null->fa=null->ch[0]=null->ch[1]=null;
    rt=null;
}

inline void rotate(SPLAY *&now){
    SPLAY *fa=now->fa,*fafa=now->fa->fa;
    int wh=now->get_wh(),fwh=fa->get_wh();

    fa->set_ch(wh,now->ch[wh^1]);
    now->set_ch(wh^1,fa);
    now->fa=fafa;
    if(fafa!=null)
        fafa->ch[fwh]=now;
}

inline void splay(SPLAY *now,SPLAY *tar){
    for(;now->fa!=tar;rotate(now))
        if(now->fa->fa!=tar)
            now->get_wh()==now->fa->get_wh()?rotate(now->fa):rotate(now);
        if(tar==null) rt=now;   
}

inline SPLAY* find(int val){
    SPLAY *now=rt;
    while(now!=null){
        if(now->val==val) break;
        if(now->val>val) now=now->ch[0];
        else now=now->ch[1];
    }
    if(now!=null) splay(now,null);
    return now;
}

void ins(int val){
    SPLAY *last=null,*now=rt,*nnow=NEW(val); 
    while(now!=null){       
        last=now;
        if(nnow->val==now->val){
            now->cnt++; now->sz++;
            splay(now,null); return;
        }
        if(nnow->val<now->val) now=now->ch[0];
        else now=now->ch[1];
    }
    if(last==now) rt=nnow;
    else if(nnow->val<last->val) last->set_ch(0,nnow);
    else last->set_ch(1,nnow);
    splay(nnow,null);   
}

void del(int val){
    SPLAY *now=find(val);
    if(now==null) return;
    if(now->cnt>1){
        now->sz--; now->cnt--; return;
    }

    if(now->ch[0]==null&&now->ch[1]==null) rt=null;
    else if(now->ch[1]==null)
        now->ch[0]->fa=null,rt=now->ch[0];
    else if(now->ch[0]==null)
        now->ch[1]->fa=null,rt=now->ch[1];
    else{
        SPLAY *ch=now->ch[0];
        while(ch->ch[1]!=null) ch=ch->ch[1];
        splay(ch,now);
        ch->set_ch(1,now->ch[1]);
        ch->fa=null;
        rt=ch;
    }
}

inline int pre(int val){
    int ans=-INF;
    SPLAY *now=rt;
    while(now!=null)
        if(now->val<val)
            ans=max(ans,now->val),now=now->ch[1];
        else now=now->ch[0];
    return ans;
}

inline int nxt(int val){
    int ans=INF;
    SPLAY *now=rt;
    while(now!=null)
        if(now->val>val)
            ans=min(ans,now->val),now=now->ch[0];
        else now=now->ch[1];
    return ans;
}

inline int rnk(int val){
    SPLAY *now=rt;
    int ls=0;
    while(now!=null){
        if(val==now->val){
            int ans=ls+now->ch[0]->sz+1;
            splay(now,null);
            return ans;
        }
        if(val<now->val) now=now->ch[0];
        else ls+=now->cnt+now->ch[0]->sz,now=now->ch[1];
    }
    return -1;
}
//inline int rnk(int val){
//    SPLAY *now=rt;
//    int ls=0;
//    while(now!=null){
//        if(val==now->val){
//            int ans=ls+now->ch[0]->sz+1;
//            splay(now,null);
//            return ans;
//        }
//        if(val<now->val) now=now->ch[0];
//        else ls+=now->ch[0]->sz+now->cnt,now=now->ch[1];
//    }
//    return -1;
//}

inline int pos(int k){
    SPLAY *now=rt;
    int ls=0;
    while(now!=null){
        int x=ls+now->ch[0]->sz;
        if(x+1<=k&&k<=x+now->cnt){
            splay(now,null);
            return now->val;
        }
        if(k<=x) now=now->ch[0];
        else ls=x+now->cnt,now=now->ch[1];
    }
    return -1;
}

int main(){
    int n=gnum(); init();
    for(int i=1;i<=n;i++){
        int opt=gnum(),x=gnum();
        switch(opt){
            case 1:ins(x);break;
            case 2:del(x);break;
            case 3:xx(rnk(x));break;
            case 4:xx(pos(x));break;
            case 5:xx(pre(x));break;
            case 6:xx(nxt(x));break;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值