[ZJOI2006]書架
題目描述
小T有一個很大的書櫃。這個書櫃的構造有些獨特,即書櫃裏的書是從上至下堆放成一列。她用1到n的正整數給每本書都編了號。
小T在看書的時候,每次取出一本書,看完後放回書櫃然後再拿下一本。由於這些書太有吸引力了,所以她看完後常常會忘記原來是放在書櫃的什麽位置。不過小T的記憶力是非常好的,所以每次放書的時候至少能夠將那本書放在拿出來時的位置附近,比如說她拿的時候這本書上面有X本書,那麽放回去時這本書上面就只可能有X-1、X或X+1本書。
當然也有特殊情況,比如在看書的時候突然電話響了或者有朋友來訪。這時候粗心的小T會隨手把書放在書櫃裏所有書的最上面或者最下面,然後轉身離開。
久而久之,小T的書櫃裏的書的順序就會越來越亂,找到特定的編號的書就變得越來越困難。於是她想請你幫她編寫一個圖書管理程序,處理她看書時的一些操作,以及回答她的兩個提問:(1)編號為X的書在書櫃的什麽位置;(2)從上到下第i本書的編號是多少。
輸入輸出格式
輸入格式:
第一行有兩個數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本書的編號。
輸出格式:
對於每一條Ask或Query語句你應該輸出一行,一個數,代表詢問的答案。
輸入輸出樣例
輸入樣例#1: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輸出樣例#1:
2 9 9 7 5 3
說明
100%的數據,n,m <= 80000
都是splay的基本操作,然而我都調成兒子了2333
總結一下小錯:
1.變量寫混(常規操作)
2.把x插入到第k大後面的時候忘了更新size(也差不多是常規操作了)
3.最致命的是我刪除的時候如果被刪除的元素是最大或者最小的話,我把根設成了前驅(後繼),而不是它們在樹上的兒子2333,這個錯的真心玄學。
所以以後一定要,think twice ,code once.
#include<bits/stdc++.h> #define ll long long #define maxn 100005 using namespace std; int f[maxn],ch[maxn][2]; int a[maxn],siz[maxn]; int n,m,pos,root,lefbig,rigsml; int cnt,S,T,u,p; char s[23]; inline void update(int x){ siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1; } inline int get(int x){ return ch[f[x]][1]==x; } inline void rotate(int x){ int fa=f[x],ffa=f[fa],tp=get(x); ch[fa][tp]=ch[x][tp^1],f[ch[fa][tp]]=fa; ch[x][tp^1]=fa,f[fa]=x; f[x]=ffa; if(ffa) ch[ffa][ch[ffa][1]==fa]=x; if(root==fa) root=x; update(fa),update(x); } inline void splay(int x,int d){ for(int fa;(fa=f[x])!=d;rotate(x)) if(f[fa]!=d) rotate(get(fa)==get(x)?fa:x); } inline int pre(int x){ x=ch[x][0]; while(ch[x][1]) x=ch[x][1]; return x; } inline int nxt(int x){ x=ch[x][1]; while(ch[x][0]) x=ch[x][0]; return x; } inline void del(int x){ splay(x,0); lefbig=pre(root),rigsml=nxt(root); if(!lefbig||!rigsml){ if(!lefbig&&!rigsml) root=0; else if(!lefbig) f[ch[root][1]]=0,root=ch[root][1]; else f[ch[root][0]]=0,root=ch[root][0]; } else{ splay(lefbig,0),splay(rigsml,root); ch[ch[root][1]][0]=0,update(ch[root][1]),update(root); } siz[x]=f[x]=ch[x][0]=ch[x][1]=0; } inline int rank(int x){ int an=siz[ch[x][0]],fa; while(x){ fa=f[x]; if(get(x)) an+=siz[ch[fa][0]]+1; x=fa; } return an; } inline int BOOK(int x){ int now=root; while(now){ if(siz[ch[now][0]]>=x) now=ch[now][0]; else{ x-=siz[ch[now][0]]+1; if(!x) return now; now=ch[now][1]; } } } inline void ins(int x,int F){ int now=root,fa=0,las; while(now){ siz[now]++; if(F<=siz[ch[now][0]]) fa=now,now=ch[now][0],las=0; else{ F-=siz[ch[now][0]]+1; fa=now,now=ch[now][1]; las=1; } } siz[x]=1,f[x]=fa,ch[fa][las]=x,update(fa); splay(x,0); } int build(int l,int r,int fa){ if(l>r) return 0; int mid=l+r>>1,O=a[mid]; f[O]=fa; ch[O][0]=build(l,mid-1,O); ch[O][1]=build(mid+1,r,O); update(O); return O; } void print(int x){ if(!x) return; print(ch[x][0]); printf("%d ",x); print(ch[x][1]); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",a+i); root=build(1,n,0); while(m--){ scanf("%s",s); if(s[0]==‘I‘){ scanf("%d%d",&S,&T); u=rank(S)+T; del(S); ins(S,u); } else if(s[0]==‘T‘){ scanf("%d",&S); del(S); ins(S,0); } else if(s[0]==‘B‘){ scanf("%d",&S); del(S); ins(S,n-1); } else if(s[0]==‘A‘){ scanf("%d",&S); printf("%d\n",rank(S)); } else{ scanf("%d",&S); printf("%d\n",BOOK(S)); } // print(root); // puts(""); } return 0; }
[ZJOI2006]書架