luogu P3369 普通平衡树

luogu P3369

主要是贴一个splay的模板:

#include<bits/stdc++.h>

using namespace std;

namespace splay{

    #define ls(x) ch[x][0]
    #define rs(x) ch[x][1]

    const int N = 1000005;
    const int inf = 2e9;
    int ch[N][2],f[N],key[N],nums[N],sz[N];
    int rt, nodeCnt;

    void clearNode(int x){//删掉某一个节点
        sz[x]=ch[x][0]=ch[x][1]=f[x]=key[x]=nums[x]=0;
    }

    bool getDir(int x){//右儿子返回1,否则返回0
        return ch[f[x]][1]==x?1:0;
    }

    void update(int x){//这里是更新一下size
        if(x){
            sz[x]=nums[x];
            if(ls(x))sz[x]+=sz[ls(x)];
            if(rs(x))sz[x]+=sz[rs(x)];
        }
    }

    void rot(int x){
        int fa=f[x],gf=f[fa],ws=getDir(x),ws1=getDir(fa),w=ch[x][ws^1];
        ch[fa][ws]=w;f[w]=fa;
        ch[gf][ws1]=x;f[x]=gf;
        ch[x][ws^1]=fa;f[fa]=x;
        update(fa);update(x);
    }

    void Splay(int x, int goal=0){
        while(f[x]!=goal){
            int fa=f[x],gf=f[fa];
            if(gf!=goal){
                if(getDir(x)==getDir(fa))rot(fa);//三点一线先旋转fa
                else rot(x);
            }
            rot(x);
        }

        if(!goal)rt=x;
    }

    void Find(int v){//有v的情况出现v,否则出现一个前驱或者后继
        if(!rt)return;

        int curNode=rt;
        while(ch[curNode][v>key[curNode]]&&v!=key[curNode]){
            curNode=ch[curNode][v>key[curNode]];
        }

        Splay(curNode,0);
    }

    void Insert(int v){
        int curNode=rt,p=0;
        while(curNode&&key[curNode]!=v){
            p=curNode;
            curNode=ch[curNode][v>key[curNode]];
        }

        if(curNode){
            ++nums[curNode];
        }else{
            curNode=++nodeCnt;
            if(p)ch[p][v>key[p]]=curNode;
            f[curNode]=p;
            ch[curNode][0]=ch[curNode][1]=0;
            nums[curNode]=sz[curNode]=1;
            key[curNode]=v;
        }
        Splay(curNode,0);
    }

    int kth(int k){//第k大的节点,插入-inf和inf的情况下,传入k+1
        int curNode=rt;
        if(sz[curNode]<k)return 0;
        while(1){
            if(k<=sz[ls(curNode)]){
                curNode=ls(curNode);
            }else if(k>sz[ls(curNode)]+nums[curNode]){
                k-=sz[ls(curNode)]+nums[curNode];
                curNode=rs(curNode);
            }else{
                return curNode;
            }
        }
    }

    int Rank(int v){
        Find(v);
        if(key[rt]>=v)return sz[ls(rt)];
        else return sz[ls(rt)]+nums[rt];
    }

    int Next(int x, int op){//op=0,前驱,op=1后继,均为节点
        Find(x);
        if(key[rt]<x&&op==0)return rt;
        if(key[rt]>x&&op==1)return rt;

        int curNode=ch[rt][op];
        while(ch[curNode][op^1])curNode=ch[curNode][op^1];

        return curNode;
    }

    void del(int x){//前驱到根,后继到右子节点,中间剩个x
        int pre=Next(x,0);
        int nxt=Next(x,1);
        Splay(pre,0),Splay(nxt,pre);

        int node=ch[nxt][0];
        if(nums[node]>=2){
            --nums[node];
            Splay(node,0);
        }
        else{
            ch[nxt][0]=0;
        }
    }


    void init(){
        Insert(inf);
        Insert(-inf);
    }

};

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
    return res*f;
}

int main(){
//    freopen("P3369_6.in","r",stdin);
//    freopen("stdout.txt","w",stdout);
    int q=read();
    splay::init();
    while(q--){
        int opt=read();
        if(opt==1){
            splay::Insert(read());
        }else if(opt==2){
            splay::del(read());
        }else if(opt==3){
            cout<<splay::Rank(read())<<endl;
        }else if(opt==4){
            cout<<splay::key[splay::kth(read()+1)]<<endl;
        }else if(opt==5){
            cout<<splay::key[splay::Next(read(),0)]<<endl;
        }else{
            cout<<splay::key[splay::Next(read(),1)]<<endl;
        }
    }

    return 0;
}

posted @ 2020-05-13 22:22  John_Ran  阅读(184)  评论(0编辑  收藏  举报