模板—Splay

Posted al-ca

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板—Splay相关的知识,希望对你有一定的参考价值。

技术图片
#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
using namespace std;
struct Splay
{
    struct node
    {
        int ch[2],fa,val,cnt,siz;
        #define l(x) tr[x].ch[0] 
        #define r(x) tr[x].ch[1]
        #define fa(x) tr[x].fa
        #define val(x) tr[x].val
        #define cnt(x) tr[x].cnt
        #define siz(x) tr[x].siz
    }tr[1000010];
    int sz,root;
    void clear(int x){fa(x)=l(x)=r(x)=val(x)=cnt(x)=siz(x)=0;}
    bool get(int x){return r(fa(x))==x;}
    int newnode(int x)
    {    
        sz++;val(sz)=x;cnt(sz)=siz(sz)=1;
        fa(sz)=l(sz)=r(sz)=0;return sz;
    }
    void pushup(int x)
    {
        if(!x)return;
        siz(x)=cnt(x);
        if(l(x))siz(x)+=siz(l(x));
        if(r(x))siz(x)+=siz(r(x));
    }
    void rotate(int x)
    {
        int old=fa(x),oldf=fa(old),which=get(x);
        tr[old].ch[which]=tr[x].ch[which^1];fa(tr[old].ch[which])=old;
        tr[x].ch[which^1]=old;fa(old)=x;fa(x)=oldf;
        if(oldf)tr[oldf].ch[tr[oldf].ch[1]==old]=x;
        pushup(old);pushup(x);
    }
    void splay(int x)
    {
        for(int f;f=fa(x);rotate(x))
        if(fa(f))rotate((get(x)==get(f))?f:x);
        root=x;
    }
    void insert(int x)
    {    
        if(!root){root=newnode(x);return;}
        int now=root,fa=0;
        while(1)
        {
            if(x==val(now)){cnt(now)++,pushup(now),pushup(fa);splay(now);return;}
            fa=now,now=tr[now].ch[val(now)<x];
            if(!now)
            {
                int tem=newnode(x);
                tr[fa].ch[x>val(fa)]=tem;
                fa(tem)=fa;val(tem)=x;
                pushup(fa);splay(tem);return;
            }
        }
    }
    int rnk(int x)
    {
        int now=root,ans=0;
        while(1)
        {
            if(x<val(now))now=l(now);
            else
            {
                ans+=siz(l(now));
                if(x==val(now)){splay(now);return ans+1;}
                ans+=cnt(now);now=r(now);
            }
        }
    }
    int kth(int x)
    {
        int now=root;
        while(1)
        {
            if(l(now)&&x<=siz(l(now)))now=l(now);
            else
            {
                int tem=siz(l(now))+cnt(now);
                if(x<=tem)return val(now);
                x-=tem;now=r(now);
            }
        }
    }
    int pre(){int now=l(root);while(r(now))now=r(now);return now;}
    int nxt(){int now=r(root);while(l(now))now=l(now);return now;}
    void del(int x)
    {
        rnk(x);
        if(cnt(root)>1){cnt(root)--;pushup(root);return;}
        if(!l(root)&&!r(root)){clear(root);root=0;return;}
        if(!l(root)){int rt=root;root=r(rt);fa(root)=0;clear(rt);return;}
        if(!r(root)){int rt=root;root=l(rt);fa(root)=0;clear(rt);return;}
        int oldrt=root,leftbig=pre();
        splay(leftbig);r(root)=r(oldrt);
        fa(r(oldrt))=root;clear(oldrt);pushup(root);
    }
}T;
signed main()
{
    int n;cin>>n;int opt,x;
    for(int i=1;i<=n;i++)
    {    
        cin>>opt>>x;
        if(opt==1)T.insert(x);
        if(opt==2)T.del(x);
        if(opt==3)cout<<T.rnk(x)<<endl;
        if(opt==4)cout<<T.kth(x)<<endl;
        if(opt==5){T.insert(x);cout<<T.val(T.pre())<<endl;T.del(x);}
        if(opt==6){T.insert(x);cout<<T.val(T.nxt())<<endl;T.del(x);}
    }
}
View Code

一个封装比较好的splay板子,不过不知道为啥常数稍大。

以上是关于模板—Splay的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1588 splay模板题

P3369 模板普通平衡树 题解(Splay)

[模板]洛谷T2042 NOI2005 维护数列 Splay

[模板]洛谷T3380 二逼平衡树 线段树套Splay

「Splay」指针版与数组版模板

[模板]洛谷T3391 文艺平衡树 链表&递归版无父指针版Splay