1. 程式人生 > >1861. [ZJOI2006]書架【平衡樹-splay】

1861. [ZJOI2006]書架【平衡樹-splay】

LG 困難 錯誤 哨兵 sin div 整數 能夠 let

Description

小T有一個很大的書櫃。這個書櫃的構造有些獨特,即書櫃裏的書是從上至下堆放成一列。她用1到n的正整數給每本書都編了號。 小T在看書的時候,每次取出一本書,看完後放回書櫃然後再拿下一本。由於這些書太有吸引力了,所以她看完後常常會忘記原來是放在書櫃的什麽位置。不過小T的記憶力是非常好的,所以每次放書的時候至少能夠將那本書放在拿出來時的位置附近,比如說她拿的時候這本書上面有X本書,那麽放回去時這本書上面就只可能有X-1、X或X+1本書。 當然也有特殊情況,比如在看書的時候突然電話響了或者有朋友來訪。這時候粗心的小T會隨手把書放在書櫃裏所有書的最上面或者最下面,然後轉身離開。 久而久之,小T的書櫃裏的書的順序就會越來越亂,找到特定的編號的書就變得越來越困難。於是她想請你幫她編寫一個圖書管理程序,處理她看書時的一些操作,以及回答她的兩個提問:(1)編號為X的書在書櫃的什麽位置;(2)從上到下第i本書的編號是多少。

Input

第一行有兩個數n,m,分別表示書的個數以及命令的條數;第二行為n個正整數:第i個數表示初始時從上至下第i個位置放置的書的編號;第三行到m+2行,每行一條命令。命令有5種形式: 1. Top S——表示把編號為S的書房在最上面。 2. Bottom S——表示把編號為S的書房在最下面。 3. Insert S T——T∈{-1,0,1},若編號為S的書上面有X本書,則這條命令表示把這本書放回去後它的上面有X+T本書; 4. Ask S——詢問編號為S的書的上面目前有多少本書。 5. Query S——詢問從上面數起的第S本書的編號。

Output

對於每一條Ask或Query語句你應該輸出一行,一個數,代表詢問的答案。

Sample Input

10 10
1 3 2 7 5 8 10 4 9 6
Query 3
Top 5
Ask 6
Bottom 3
Ask 3
Top 6
Insert 4 -1
Query 5
Query 2
Ask 2

Sample Output

2
9
9
7
5
3

HINT

數據範圍

100%的數據,n,m < = 80000

這個題還是很裸的,只不過我犯了一個非常sb的錯誤然後調了好久emm……
操作原理在函數中
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #define N (100000+100)
  6 using namespace std;
  7 int Size[N],Key[N];//key存編號
  8 int Father[N],Son[N][2];
  9 int n,m,Root,a[N],x,t;
 10 int point[N];//存編號i對應的是splay的哪個點
 11 char s[N];
 12 
 13 int Get(int x){return Son[Father[x]][1]==x;}
 14 void Update(int x){Size[x]=Size[Son[x][0]]+Size[Son[x][1]]+1;}
 15 void Clear(int x){Father[x]=Son[x][0]=Son[x][1]=Size[x]=0;}
 16 int Pre(){int now=Son[Root][0];    while (Son[now][1]) now=Son[now][1];return now;}
 17 int Next(){    int now=Son[Root][1];while (Son[now][0]) now=Son[now][0];return now;}
 18 
 19 void Build(int l,int r,int fa)
 20 {
 21     if (l>r) return;
 22     if (l==r)
 23     {
 24         Size[l]=1;
 25         Key[l]=a[l];
 26         Father[l]=fa;
 27         Son[fa][l>fa]=l;
 28         return;
 29     }
 30     int mid=(l+r)/2;
 31     Build(l,mid-1,mid);
 32     Build(mid+1,r,mid);
 33     Father[mid]=fa;
 34     Son[fa][mid>fa]=mid;
 35     Key[mid]=a[mid];
 36     Update(mid);
 37 }
 38 
 39 void Rotate(int x)
 40 {
 41     int wh=Get(x);
 42     int fa=Father[x],fafa=Father[fa];
 43     Son[fa][wh]=Son[x][wh^1];
 44     Father[fa]=x;
 45     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
 46     Son[x][wh^1]=fa;
 47     Father[x]=fafa;
 48     if (fafa) Son[fafa][Son[fafa][1]==fa]=x;
 49     Update(fa);
 50     Update(x);
 51 }
 52 
 53 void Splay(int x)
 54 {
 55     for (int fa; fa=Father[x]; Rotate(x))
 56         if (Father[fa])
 57             Rotate(Get(fa)==Get(x)?fa:x);
 58     Root=x;
 59 }
 60 
 61 int Findx(int x)
 62 {
 63     int now=Root;
 64     while (1)
 65         if (x<=Size[Son[now][0]])
 66             now=Son[now][0];
 67         else
 68         {
 69             x-=Size[Son[now][0]];
 70             if (x==1)
 71             {
 72                 Splay(now);
 73                 return Key[now];
 74             }
 75             x--;
 76             now=Son[now][1];
 77         }
 78 }
 79 
 80 void Delete(int x)
 81 {
 82     Findx(x);
 83     if (!Son[Root][0] && !Son[Root][1])
 84     {
 85         Clear(Root);
 86         Root=0;
 87         return;
 88     }
 89     if (!Son[Root][1])
 90     {
 91         Root=Son[Root][0];
 92         Clear(Father[Root]);
 93         Father[Root]=0;
 94         return;
 95     }
 96     if (!Son[Root][0])
 97     {
 98         Root=Son[Root][1];
 99         Clear(Father[Root]);
100         Father[Root]=0;
101         return;
102     }
103     Splay(x);
104     int pre=Pre(),old=x;
105     Splay(pre);
106     Son[Root][1]=Son[old][1];
107     Father[Son[old][1]]=Root;
108     Clear(old);
109     Update(Root);
110 }
111 
112 void Top(int x)//就是將一個點刪除掉然後放到哨兵節點1的右兒子上。若右兒子有點就把原來的右兒子當做插入節點的右兒子
113 {
114     Delete(x);
115     int now=Root;
116     while (Son[now][0]) now=Son[now][0];
117     int old=Son[now][1];
118     Father[x]=now;
119     Son[now][1]=x;
120     Father[old]=x;
121     Son[x][1]=old;
122     Update(x);
123     Splay(x);
124 }
125 
126 void Bottom(int x)//同上
127 {
128     Delete(x);
129     int now=Root;
130     while (Son[now][1]) now=Son[now][1];
131     int old=Son[now][0];
132     Father[x]=now;
133     Son[now][0]=x;
134     Father[old]=x;
135     Son[x][0]=old;
136     Update(now);
137     Splay(x);
138 }
139 
140 void Ins(int x,int t)//-1(+1同理):先把x刪掉,再把x前驅splay到根,再把x插到根的前驅位置的葉子
141 {
142     int y,z;
143     if (t==-1)
144     {
145         Splay(x);
146         y=Pre();
147         Delete(x);
148         Splay(y);
149         z=Pre();
150         Father[x]=z;
151         Son[z][1]=x;
152         Size[x]=1;
153         Update(z);
154         Splay(x);
155     }
156     if (t==1)
157     {
158         Splay(x);
159         y=Next();
160         Delete(x);
161         Splay(y);
162         z=Next();
163         Father[x]=z;
164         Son[z][0]=x;
165         Size[x]=1;
166         Update(z);
167         Splay(x);
168     }
169 
170 }
171 
172 int Ask(int x)//emmm……
173 {
174     Splay(x);
175     return Size[Son[x][0]]-1;
176 }
177 
178 int main()
179 {
180     scanf("%d%d",&n,&m);
181     for (int i=1; i<=n; ++i)
182     {
183         scanf("%d",&a[i+1]);
184         point[a[i+1]]=i+1;
185     }
186     Build(1,n+2,0);
187     Root=(n+3)/2;
188     for (int i=1; i<=m; ++i)
189     {
190         scanf("%s%d",&s,&x);
191         if (s[0]==T) Top(point[x]);
192         if (s[0]==B) Bottom(point[x]);
193         if (s[0]==I) scanf("%d",&t),Ins(point[x],t);
194         if (s[0]==A) printf("%d\n",Ask(point[x]));
195         if (s[0]==Q) printf("%d\n",Findx(x+1));
196     }
197 }

1861. [ZJOI2006]書架【平衡樹-splay】