loj 104 普通平衡树splay

Posted nervendnig

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了loj 104 普通平衡树splay相关的知识,希望对你有一定的参考价值。

int n,root;//@树根@
class splaytreepublic:
    int fa[maxn],son[maxn][2],sz[maxn],val[maxn],cnt[maxn];
    int tot;//@root根val权值,cnt重复次数,sz子树大小@
    inline void pushup(int now)
        sz[now]=sz[son[now][0]]+sz[son[now][1]]+cnt[now];
    //@更新当前节点信息@
    inline bool getson(int now) 
        return now==son[fa[now]][1];
    //@真为右儿子@
    inline void clear(int now)
        fa[now]=son[now][0]=son[now][1]=sz[now]=val[now]=cnt[now]=0;
    //@清空节点@
    inline void rotate(int now)
        int f=fa[now],gf=fa[fa[now]],flag=getson(now);
        son[f][flag]=son[now][flag^1];
        fa[son[now][flag^1]]=f;
        son[now][flag^1]=f;
        fa[f]=now;fa[now]=gf;
        if(gf) son[gf][f==son[gf][1]]=now;
        pushup(now);pushup(f);
    //@旋转一层@
    void splay(int now)
        for(int f=fa[now];f=fa[now],f;rotate(now))
            if(fa[f]) rotate(getson(now)==getson(f)?f:now);
        root=now;
    //@旋转到根@
    void insert(int x,int now=root,int f=0)
        if(!now)
            now=++tot;
            val[now]=x,cnt[now]++;
            if(!root)root=now;
            pushup(now);
            if(f)
                fa[now]=f;
                son[f][val[f]<x]=now;
                pushup(f);
                splay(now);
            
        else if(val[now]==x)
            ++cnt[now];
            pushup(now);pushup(f);
            splay(now);
        else insert(x,son[now][val[now]<x],now);
    //@插入新点@
    int getrank(int x,int now=root,int ans=0)
        while(1)
            if(x<val[now]) now=son[now][0];
            else 
                ans+=sz[son[now][0]];
                if(x==val[now]) return splay(now),ans+1;
                ans+=cnt[now];now=son[now][1];
            
        
    //@多少个元素小于[email protected]
    int get(int k,int now=root)
        while(1)
            if(son[now][0]&&k<=sz[son[now][0]]) now=son[now][0];
            else 
                k-=cnt[now]+sz[son[now][0]];
                if(k<=0) return val[now];
                now=son[now][1];
            
        
    //查询第k大元素
    int pre()
        int now=son[root][0];
        while(son[now][1]) now=son[now][1];
        return now;
    //@前驱@
    int nxt()
        int now=son[root][1];
        while(son[now][0]) now=son[now][0];
        return now;
    //@后缀@
    int lower(int x)
        insert(x);int ans=val[pre()];erase(x);
        return ans;
    //@查询前驱@@
    int upper(int x)
        insert(x);int ans=val[nxt()];erase(x);
        return ans;
    //@查询后缀@
    void erase(int x)
        getrank(x);
        if(cnt[root]>1)
            --cnt[root];
            pushup(root);
        else if(!son[root][0]&&!son[root][1])
            clear(root);
            root=0;
        else if(!son[root][0]||!son[root][1])
            int t=root;
            if(!son[root][0]) root=son[root][1];
            else root=son[root][0];
            fa[root]=0;
            clear(t);
        else 
            int now=pre(),t=root;
            splay(now);
            fa[son[t][1]]=now;
            son[now][1]=son[t][1];
            clear(t);
            pushup(root);
        
    //@删除x元素@
tree;
int main() 
    cin>>n;
    while(n--)
        int opt,x;cin>>opt>>x;
        if(opt==1) tree.insert(x);
        if(opt==2) tree.erase(x);
        if(opt==3) cout<<tree.getrank(x)<<endl;
        if(opt==4) cout<<tree.get(x)<<endl;
        if(opt==5) cout<<tree.lower(x)<<endl;
        if(opt==6) cout<<tree.upper(x)<<endl;
    
	return 0;

整理一下板子

换了种写法 递归和循环都有,

属于比赛的时候翘起来很快的写法,速度比oiwiki上的板子慢了100ms左右吧

以上是关于loj 104 普通平衡树splay的主要内容,如果未能解决你的问题,请参考以下文章

[平衡树-Splay]营业额统计

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

普通平衡树[splay]

洛谷P3369普通平衡树(splay)

bzoj3224Tyvj 1728 普通平衡树 平衡树的三种姿势 :splay,Treap,ScapeGoat_Tree

BZOJ 3224 普通平衡树 平衡树的两种姿势:SBT,splay