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;
}