1861. [ZJOI2006]書架【平衡樹-splay】
阿新 • • 發佈:2018-04-01
LG 困難 錯誤 哨兵 sin div 整數 能夠 let
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
9
9
7
5
3
這個題還是很裸的,只不過我犯了一個非常sb的錯誤然後調了好久emm……
操作原理在函數中
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 101 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
29
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】