1. 程式人生 > >【總結】 伸展樹Splay

【總結】 伸展樹Splay

挖坑待補

前言

感覺我在聯賽還差4天的時候學習Splay有點慌,但還是要學一下。

定義

我們先對Splay的陣列進行一些定義:

struct node{
    int ff,siz,cnt,ch[2],val;
    //ff表示父親,siz表示子樹大小,ch表示兒子,cnt表示與這個點權值相同的點的個數,val表示權值。
}t[N<<2];

操作

我們的Splay應該要支援以下幾個操作:

  • 插入
  • 刪除
  • 查詢排名為k的數
  • 查詢k的排名
  • 查詢k的前驅
  • 查詢k的後繼
  • 分裂(不會)
  • 合併(啟發式合併)

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
const int N=500010;
int root,tot;
inline int gi(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
class SplayTree{
private:
    struct node{
        int ff,siz,cnt,ch[2],val;
        //ff表示父親,siz表示子樹大小,ch表示兒子,cnt表示與這個點權值相同的點的個數,val表示權值。
    }t[N<<2];
    inline void pushup(int x){t[x].siz=t[x].cnt+t[t[x].ch[0]].siz+t[t[x].ch[1]].siz;}
    inline void rotate(int x){
        int y=t[x].ff,z=t[y].ff;
        int k=(x==t[y].ch[1]);
        t[z].ch[y==t[z].ch[1]]=x;
        t[x].ff=z;
        t[y].ch[k]=t[x].ch[k^1];
        t[t[x].ch[k^1]].ff=y;
        t[x].ch[k^1]=y;
        t[y].ff=x;
        pushup(y);pushup(x);
    }
public:
    inline void Splay(int x,int goal){
        while(t[x].ff!=goal){
            int y=t[x].ff,z=t[y].ff;
            if(z!=goal)
                (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
            rotate(x);
        }
        if(!goal)root=x;
    }
    inline void find(int x){
        int u=root;
        if(!u)return;
        while(t[u].val!=x && t[u].ch[x>t[u].val])
            u=t[u].ch[x>t[u].val];
        Splay(u,0);
    }
    inline void Insert(int x){
        int u=root,ff=0;
        while(u && t[u].val!=x){ff=u;u=t[u].ch[x>t[u].val];}
        if(u)t[u].cnt++;
        else{
            u=++tot;
            t[u].cnt=t[u].siz=1;t[u].val=x;
            t[u].ff=ff;t[u].ch[0]=t[u].ch[1]=0;
            if(ff)t[ff].ch[x>t[ff].val]=u;
        }
        Splay(u,0);
    }
    inline int Next(int x,int f){//f=1表示後繼,f=0表示前驅
        find(x);
        int u=root;
        if(t[u].val>x && f)return u;
        if(t[u].val<x && !f)return u;
        u=t[u].ch[f];
        while(t[u].ch[f^1])u=t[u].ch[f^1];
        return u;
    }
    inline void Delete(int x){
        int last=Next(x,0),nxt=Next(x,1);
        Splay(last,0);Splay(nxt,last);
        int del=t[nxt].ch[0];
        if(t[del].cnt>1){t[del].cnt--;Splay(del,0);}
        else t[nxt].ch[0]=0;
    }
    inline int kth(int x){
        int u=root;
        if(t[u].siz<x)return 0;
        while(1){
            int y=t[u].ch[0];
            if(t[y].siz<x && t[y].siz+t[u].cnt>=x)return t[u].val;
            if(t[y].siz>=x)u=y;
            else{
                x-=t[y].siz+t[u].cnt;
                u=t[u].ch[1];
            }
        }
    }
    inline int Val(int u){
        return t[u].val;
    }
    inline int ch0size(){
        return t[t[root].ch[0]].siz;
    }
}Splay;
int main(){
    int n=gi();
    Splay.Insert(2147483647);
    Splay.Insert(-2147483648);
    while(n--){
        int opt=gi(),x=gi();
        if(opt==1)Splay.Insert(x);
        if(opt==2)Splay.Delete(x);
        if(opt==3){
            Splay.find(x);
            printf("%d\n",Splay.ch0size());
        }
        if(opt==4)printf("%d\n",Splay.kth(x+1));
        if(opt==5)printf("%d\n",Splay.Val(Splay.Next(x,0)));
        if(opt==6)printf("%d\n",Splay.Val(Splay.Next(x,1)));
    }
    return 0;
}