[題解]bzoj4825 HNOI2017單旋

Description

H 國是一個熱愛寫代碼的國家,那裏的人們很小去學校學習寫各種各樣的數據結構。伸展樹(splay)是一種數據結構,因爲代碼好寫,功能多,效率高,掌握這種數據結構成爲了 H 國的必修技能。有一天,邪惡的“卡”帶着他的邪惡的“常數”來企圖毀滅 H 國。“卡”給 H 國的人洗腦說,splay 如果寫成單旋的,將會更快。“卡”稱“單旋 splay”爲“spaly”。雖說他說的很沒道理,但還是有 H 國的人相信了,小 H 就是其中之一,spaly 馬上成爲他的信仰。 而 H 國的國王,自然不允許這樣的風氣蔓延,國王構造了一組數據,數據由 m 個操作構成,他知道這樣的數據肯定打垮 spaly,但是國王還有很多很多其他的事情要做,所以統計每個操作所需要的實際代價的任務就交給你啦。
數據中的操作分爲五種:
1. 插入操作:向當前非空 spaly 中插入一個關鍵碼爲 key 的新孤立節點。插入方法爲,先讓 key 和根比較,如果 key 比根小,則往左子樹走,否則往右子樹走,如此反覆,直到某個時刻,key 比當前子樹根 x 小,而 x 的左子樹爲空,那就讓 key 成爲 x 的左孩子; 或者 key 比當前子樹根 x 大,而 x 的右子樹爲空,那就讓 key 成爲 x 的右孩子。該操作的代價爲:插入後,key 的深度。特別地,若樹爲空,則直接讓新節點成爲一個單個節點的樹。(各節點關鍵碼互不相等。對於“深度”的解釋見末尾對 spaly 的描述)。
2. 單旋最小值:將 spaly 中關鍵碼最小的元素 xmin 單旋到根。操作代價爲:單旋前 xmin 的深度。(對於單旋操作的解釋見末尾對 spaly 的描述)。
3. 單旋最大值:將 spaly 中關鍵碼最大的元素 xmax 單旋到根。操作代價爲:單旋前 xmax 的深度。
4. 單旋刪除最小值:先執行 2 號操作,然後把根刪除。由於 2 號操作之後,根沒有左子樹,所以直接切斷根和右子樹的聯繫即可(具體見樣例解釋)。 操作代價同 2 號操 作。
5. 單旋刪除最大值:先執行 3 號操作,然後把根刪除。 操作代價同 3 號操作。對於不是 H 國的人,你可能需要了解一些 spaly 的知識,才能完成國王的任務:
a. spaly 是一棵二叉樹,滿足對於任意一個節點 x,它如果有左孩子 lx,那麼 lx 的關鍵碼小於 x 的關鍵碼。如果有右孩子 rx,那麼 rx 的關鍵碼大於 x 的關鍵碼。
b. 一個節點在 spaly 的深度定義爲:從根節點到該節點的路徑上一共有多少個節點(包括自己)。
c. 單旋操作是對於一棵樹上的節點 x 來說的。一開始,設 f 爲 x 在樹上的父親。如果 x 爲 f 的左孩子,那麼執行 zig(x) 操作(如上圖中,左邊的樹經過 zig(x) 變爲了右邊的樹),否則執行 zag(x) 操作(在上圖中,將
右邊的樹經過 zag(f) 就變成了左邊的樹)。每當執 行一次 zig(x) 或者 zag(x),x 的深度減小 1,如此反覆,直到 x 爲根。總之,單旋 x 就是通過反覆執行 zig 和 zag 將 x 變爲根。

Input

第一行單獨一個正整數 m。
接下來 m 行,每行描述一個操作:首先是一個操作編號 c∈[1,5],即問題描述中給出的五種操作中的編號,若 c = 1,則再輸入一個非負整數 key,表示新插入節點的關鍵碼。1≤m≤10^5,1≤key≤10^9
所有出現的關鍵碼互不相同。任何一個非插入操作,一定保證樹非空。在未執行任何操作之前,樹爲空

Output

輸出共 m 行,每行一個整數,第 i 行對應第 i 個輸入的操作的代價。

Sample Input

5
1 2
1 1
1 3
4
5

Sample Output

1
2
2
2
2

Solution

單旋的時候對樹的形態破壞不大,只會影響少數節點,所以用Splay維護深度就好了,自己手動分析一下影響,同時記錄下在真正的Spaly樹上的父親、左右兒子。細節多如牛毛,真心難調。

代碼:

#include<cstdio>
#include<algorithm>
using namespace std;

template<typename T>inline void read(T &x){
    T f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    x*=f;
}

const int maxn=100010,inf=0x7fffffff;
struct node{
    int ch[2],fa,key,dep,add,rfa,rch[2];
    node(){
        ch[0]=ch[1]=rch[0]=rch[1]=0;
        rfa=fa=key=dep=add=0;
    }
}T[maxn];
struct Splay_Tree{
    int root,num,rroot;
    Splay_Tree(){rroot=root=num=0;}
    int getson(int x){
        return x==T[T[x].fa].ch[1];
    }
    void pushdown(int x){
        if(!T[x].add)return;
        if(T[x].ch[0]){
            T[T[x].ch[0]].add+=T[x].add;
            T[T[x].ch[0]].dep+=T[x].add;
        }
        if(T[x].ch[1]){
            T[T[x].ch[1]].add+=T[x].add;
            T[T[x].ch[1]].dep+=T[x].add;
        }
        T[x].add=0;
    }
    void rotate(int x){
        int fa=T[x].fa,fafa=T[fa].fa,k=getson(x);
        pushdown(fa);pushdown(x);
        T[fa].ch[k]=T[x].ch[k^1];
        if(T[x].ch[k^1])T[T[x].ch[k^1]].fa=fa;
        T[x].ch[k^1]=fa;T[fa].fa=x;T[x].fa=fafa;
        if(fafa)T[fafa].ch[fa==T[fafa].ch[1]]=x;
    }
    void Splay(int x,int f=0){
        for(int fa;(fa=T[x].fa)!=f;rotate(x))
            if(T[fa].fa!=f)rotate(getson(x)==getson(fa)?fa:x);
        if(!f)root=x;
    }
    void Insert(int val,int dp){
        if(!root){
            T[root=++num].key=val;
            T[root].dep=dp;rroot=num;
            return;
        }
        int x=root,fa;
        while(x){
            pushdown(fa=x);
            x=T[x].ch[val>T[x].key];
        }
        T[fa].ch[val>T[fa].key]=++num;
        T[num].key=val;T[num].dep=dp;
        T[num].fa=fa;
        Splay(num);
    }
    int Find(int val){
        int x=root;
        while(1){
            pushdown(x);
            if(T[x].key==val)return x;
            x=T[x].ch[val>T[x].key];
        }
    }
    int Getpre(int val){
        int x=root,ans=-inf;
        while(x){
            pushdown(x);
            if(T[x].key<val)ans=x,x=T[x].ch[1];
            else x=T[x].ch[0];
        }
        return ans;
    }
    int Getsuf(int val){
        int x=root,ans=inf;
        while(x){
            pushdown(x);
            if(T[x].key>val)ans=x,x=T[x].ch[0];
            else x=T[x].ch[1];
        }
        return ans;
    }
    int Getmin(){
        int x=root;
        while(T[x].ch[0])pushdown(x),x=T[x].ch[0];
        return x;
    }
    int Getmax(){
        int x=root;
        while(T[x].ch[1])pushdown(x),x=T[x].ch[1];
        return x;
    }
}tree;
int n;

int main(){
    read(n);
    while(n--){
        int opt,x,ans;
        read(opt);
        if(opt==1){
            read(x);
            int l=tree.Getpre(x);
            int r=tree.Getsuf(x);
            if(l<0&&r==inf)tree.Insert(x,ans=1);
            else if(l<0){
                tree.Insert(x,ans=T[r].dep+1);
                T[T[r].rch[0]=tree.num].rfa=r;
            }
            else if(r==inf){
                tree.Insert(x,ans=T[l].dep+1);
                T[T[l].rch[1]=tree.num].rfa=l;
            }
            else{
                if(T[l].dep>T[r].dep){
                    tree.Insert(x,ans=T[l].dep+1);
                    T[T[l].rch[1]=tree.num].rfa=l;
                }
                else{
                    tree.Insert(x,ans=T[r].dep+1);
                    T[T[r].rch[0]=tree.num].rfa=r;
                }
            }
        }
        else if(opt==2){
            x=tree.Getmin();ans=T[x].dep;
            T[x].dep=1;tree.Splay(x);
            if(T[x].rfa){
                if(T[x].ch[1]){
                    T[T[x].ch[1]].add++;
                    T[T[x].ch[1]].dep++;
                }
                if(T[x].rch[1]){
                    int temp=T[x].rch[1];
                    T[temp].rfa=T[x].rfa;
                    T[T[x].rfa].rch[0]=temp;
                    tree.Splay(T[x].rfa,x);
                    T[T[T[x].rfa].ch[0]].add--;
                    T[T[T[x].rfa].ch[0]].dep--;
                }
                else T[T[x].rfa].rch[0]=0;
                T[x].rch[1]=tree.rroot;
                T[tree.rroot].rfa=x;
                T[x].rfa=T[x].rch[0]=0;
                tree.rroot=x;
            }
        }
        else if(opt==3){
            x=tree.Getmax();ans=T[x].dep;
            T[x].dep=1;tree.Splay(x);
            if(T[x].rfa){
                if(T[x].ch[0]){
                    T[T[x].ch[0]].add++;
                    T[T[x].ch[0]].dep++;
                }
                if(T[x].rch[0]){
                    int temp=T[x].rch[0];
                    T[temp].rfa=T[x].rfa;
                    T[T[x].rfa].rch[1]=temp;
                    tree.Splay(T[x].rfa,x);
                    T[T[T[x].rfa].ch[1]].add--;
                    T[T[T[x].rfa].ch[1]].dep--;
                }
                else T[T[x].rfa].rch[1]=0;
                T[x].rch[0]=tree.rroot;
                T[tree.rroot].rfa=x;
                T[x].rfa=T[x].rch[1]=0;
                tree.rroot=x;
            }
        }
        else if(opt==4){
            x=tree.Getmin();ans=T[x].dep;
            T[x].dep=1;tree.Splay(x);
            if(T[x].rfa){
                if(T[x].ch[1]){
                    T[T[x].ch[1]].add++;
                    T[T[x].ch[1]].dep++;
                }
                if(T[x].rch[1]){
                    int temp=T[x].rch[1];
                    T[temp].rfa=T[x].rfa;
                    T[T[x].rfa].rch[0]=temp;
                    tree.Splay(T[x].rfa,x);
                    T[T[T[x].rfa].ch[0]].add--;
                    T[T[T[x].rfa].ch[0]].dep--;
                }
                else T[T[x].rfa].rch[0]=0;
                T[x].rch[1]=tree.rroot;
                T[tree.rroot].rfa=x;
                T[x].rfa=T[x].rch[0]=0;
                tree.rroot=x;
            }
            tree.pushdown(tree.root);
            tree.rroot=T[tree.rroot].rch[1];
            T[tree.rroot].rfa=0;
            tree.root=T[tree.root].ch[1];
            T[tree.root].fa=0;
            if(tree.root){
                T[tree.root].add--;
                T[tree.root].dep--;
            }
        }
        else if(opt==5){
            x=tree.Getmax();ans=T[x].dep;
            T[x].dep=1;tree.Splay(x);
            if(T[x].rfa){
                if(T[x].ch[0]){
                    T[T[x].ch[0]].add++;
                    T[T[x].ch[0]].dep++;
                }
                if(T[x].rch[0]){
                    int temp=T[x].rch[0];
                    T[temp].rfa=T[x].rfa;
                    T[T[x].rfa].rch[1]=temp;
                    tree.Splay(T[x].rfa,x);
                    T[T[T[x].rfa].ch[1]].add--;
                    T[T[T[x].rfa].ch[1]].dep--;
                }
                else T[T[x].rfa].rch[1]=0;
                T[x].rch[0]=tree.rroot;
                T[tree.rroot].rfa=x;
                T[x].rfa=T[x].rch[1]=0;
                tree.rroot=x;
            }
            tree.pushdown(tree.root);
            tree.rroot=T[tree.rroot].rch[0];
            T[tree.rroot].rfa=0;
            tree.root=T[tree.root].ch[0];
            T[tree.root].fa=0;
            if(tree.root){
                T[tree.root].add--;
                T[tree.root].dep--;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章