BZOJ1861: [Zjoi2006]Book 書架
題解:Splay
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100005;
int ls[N],rs[N],siz[N],fa[N],a[N],n,m,root,S,T;
char c[11];
void Pushup(int x)
{
siz[x]=siz[ls[x]]+siz[rs[x]]+1;
}
void print()
{
cout<<"root="<<root<<endl;
for(int i=0;i<=n+2;i++) printf("i=%d ls=%d rs=%d fa=%d siz=%d\n",i,ls[i],rs[i],fa[i],siz[i]);
}
void Rotate(int x,int &k)
{
int y=fa[x],z=fa[y];
if(k==y) k=x;
else
{
if(y==ls[z]) ls[z]=x;
else rs[z]=x;
}
fa[x]=z;
fa[y]=x;
if(ls[y]==x)
{
ls[y]=rs[x];
fa[rs[x]]=y;
rs[x]=y;
}
else
{
rs[y]=ls[x];
fa[ls[x]]=y;
ls[x]=y;
}
Pushup(y);
Pushup(x);
}
void Splay(int x,int &k)
{
while(x!=k)
{
int y=fa[x],z=fa[y];
if(y!=k)
{
if(ls[z]==y^ls[y]==x) Rotate(x,k);
else Rotate(y,k);
}
Rotate(x,k);
}
}
void Build(int l,int r,int f)
{
if(l>r) return;
if(l==r)
{
siz[a[l]]=1;
fa[a[l]]=a[f];
if(l<f) ls[a[f]]=a[l];
else rs[a[f]]=a[l];
return;
}
int mid=(l+r)>>1;
Build(l,mid-1,mid);
Build(mid+1,r,mid);
Pushup(a[mid]);
fa[a[mid]]=a[f];
if(mid<f) ls[a[f]]=a[mid];
else rs[a[f]]=a[mid];
}
int tot;
int Getnum(int x,int rank)
{
if(rank==siz[ls[x]]+1) return x;
else if(rank<=siz[ls[x]]) return Getnum(ls[x],rank);
else return Getnum(rs[x],rank-siz[ls[x]]-1);
}
int Getrank(int x)
{
Splay(x,root);
return siz[ls[x]]+1;
}
void Del(int x)
{
int tmp=Getrank(x);
int y=Getnum(root,tmp-1),z=Getnum(root,tmp+1);
Splay(y,root);
Splay(z,rs[y]);
ls[z]=fa[x]=0;
Pushup(z);
}
void Ins(int nu,int x)
{
int u=Getnum(root,nu);
int v=Getnum(root,nu+1);
Splay(u,root);
Splay(v,rs[u]);
ls[v]=x;
fa[x]=v;
Pushup(v);
}
void Top(int x)
{
int u=Getnum(root,2);
Splay(u,root);
fa[S]=x,ls[x]=S;
fa[x]=u,ls[u]=x;
Pushup(S),Pushup(x),Pushup(u);
}
void Bot(int x)
{
int u=Getnum(root,n);
Splay(u,root);
fa[T]=x,rs[x]=T;
fa[x]=u,rs[u]=x;
Pushup(T),Pushup(x),Pushup(u);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=2;i<=n+1;i++) scanf("%d",&a[i]);
S=n+1,T=n+2;
a[1]=S,a[n+2]=T;
root=a[(n+3)>>1];
Build(1,n+2,0);
int x,y,u,v;
while(m--)
{
scanf("%s%d",c,&x);
if(c[0]=='Q') printf("%d\n",Getnum(root,x+1));
else if(c[0]=='A') printf("%d\n",Getrank(x)-2);
else if(c[0]=='I')
{
scanf("%d",&y);
if(y==0) continue;
int tmp=Getrank(x);
Del(x);
if(y==-1) Ins(tmp-2,x);
if(y==1) Ins(tmp,x);
}
else
{
Del(x);
if(c[0]=='T') Top(x);
if(c[0]=='B') Bot(x);
}
}
}
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
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
9
9
7
5
3
HINT
數據範圍