【POJ3580】【块状链表】SuperMemo
Description
Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A1, A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:
- ADD x y D: Add D to each number in sub-sequence {Ax ... Ay}. For example, performing "ADD 2 4 1" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5, 5}
- REVERSE x y: reverse the sub-sequence {Ax ... Ay}. For example, performing "REVERSE 2 4" on {1, 2, 3, 4, 5} results in {1, 4, 3, 2, 5}
- REVOLVE x y T: rotate sub-sequence {Ax ... Ay} T times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
- INSERT x P: insert P after Ax. For example, performing "INSERT 2 4" on {1, 2, 3, 4, 5} results in {1, 2, 4, 3, 4, 5}
- DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
- MIN x y: query the participant what is the minimum number in sub-sequence {Ax ... Ay}. For example, the correct answer to "MIN 2 4" on {1, 2, 3, 4, 5} is 2
To make the show more interesting, the participant is granted a chance to turn to someone else that means when Jackson feels difficult in answering a query he may call you for help. You task is to watch the TV show and write a program giving the correct answer to each query in order to assist Jackson whenever he calls.
Input
The first line contains n (n ≤ 100000).
The following n lines describe the sequence.
Then follows M (M ≤ 100000), the numbers of operations and queries.
The following M lines describe the operations and queries.
Output
For each "MIN" query, output the correct answer.
Sample Input
5 1 2 3 4 5 2 ADD 2 4 1 MIN 4 5
Sample Output
5
Source
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #include <utility> 7 #include <iomanip> 8 #include <string> 9 #include <cmath> 10 #include <queue> 11 #include <assert.h> 12 #include <map> 13 #include <ctime> 14 #include <cstdlib> 15 #define LOCAL 16 const int MAXN = 100000 + 10; 17 const int INF = 0x7fffffff; 18 const int SIZE = 450; 19 using namespace std; 20 struct Node{ 21 int shu[SIZE + 2]; 22 int Min, addn, size;//块内最小值,需要加的n 23 Node *l, *r; 24 bool turn, add;//turn为翻转标记,add为增加标记 25 26 Node(){ 27 Min = INF; addn = size = 0; 28 l = r = NULL; 29 turn = add = 0; 30 } 31 void update(){ 32 if (turn){ 33 for (int i = 1; i <= (size>>1); i++) swap(shu[i], shu[size - i + 1]); 34 turn = 0; 35 } 36 if (add){ 37 add = 0; 38 for (int i = 1; i <= size; i++) shu[i] += addn; 39 Min += addn; 40 addn = 0; 41 } 42 } 43 //统计最小值 44 void Count(){ 45 update(); 46 Min = INF; 47 for (int i = 1; i <= size; i++) Min = min(shu[i], Min); 48 } 49 }; 50 struct Block{ 51 Node *head, *p; 52 int dir;//剩余的位置 53 54 Block(){head = new Node;} 55 //分裂p块 56 Node *split(Node *&t, int x){//从p的x位置开始分裂 57 t->update(); 58 Node *p2 = new Node; 59 p2->r = t->r; 60 p2->l = t; 61 if (t->r != NULL) t->r->l = p2; 62 t->r = p2; 63 //[1,x]分到p中,[x+1,p->size]在p2中 64 memcpy(&p2->shu[1], &t->shu[x + 1], sizeof(int) * (t->size - x)); 65 p2->size = t->size - x;//第一次写反了QAQ 66 t->size = x; 67 68 t->Count(); 69 p2->Count(); 70 return p2; 71 } 72 Node *merge(Node *a, Node *b){ 73 a->update(); 74 b->update(); 75 Node *t = new Node; 76 t->r = b->r; 77 t->l = a->l; 78 if (b->r != NULL) b->r->l = t; 79 if (a->l != NULL) a->l->r = t; 80 t->size = a->size + b->size; 81 memcpy(&t->shu[1], &a->shu[1], sizeof(int) * (a->size)); 82 memcpy(&t->shu[a->size + 1], &b->shu[1], sizeof(int) * (b->size)); 83 t->Count(); 84 if (a->l == NULL)//说明是head 85 head = t; 86 delete a; 87 delete b; 88 return t; 89 } 90 void find(int x){ 91 //路径压缩 92 int cnt = 0; 93 p = head; 94 while (cnt + p->size < x){ 95 cnt += p->size; 96 //if ((p->l != NULL) && (p->l->size + p->size <= (SIZE>>1))) 97 //p = merge(p->l, p); 98 if (p->size == 0 && p != head){//删除空白块 99 p = p->l; 100 if (p->r != NULL) p->r = p->r->r; 101 else p->r = NULL; 102 if (p->r != NULL) p->r->l = p; 103 } 104 p = p->r; 105 } 106 dir = x - cnt;//注意这个值是直接在pos数组中的 107 } 108 //在pos位置插入num个数 109 void Insert(int pos, int num, int *data){ 110 Node *p2; 111 find(pos); 112 if (pos == 0 && head->size == 0) goto w; 113 p->update(); 114 //需要分裂 115 if (dir != p->size) { 116 p = split(p, dir); 117 p = p->l; 118 p = split(p, p->size); 119 }else p = split(p, dir); 120 121 w:int i = 1; 122 while (i <= num){ 123 int tmp = min(SIZE - p->size, num - i + 1); 124 memcpy(&p->shu[p->size + 1], &data[i], sizeof(int) * (tmp)); 125 p->size += tmp; 126 i += tmp; 127 if (num >= i){ 128 p->Count(); 129 p = split(p, p->size); 130 } 131 } 132 p->Count(); 133 } 134 void Delete(int pos, int num){//从pos位置开始删除num个数字 135 find(pos); 136 Node *p2; 137 while (num > 0){ 138 if ((dir == 1) && (num >= p->size)){ 139 num -= p->size; 140 if (p->l != NULL) p->l->r = p->r; 141 else head = p->r; 142 if (p->r != NULL) p->r->l = p->l; 143 p2 = p; 144 p = p->r; 145 delete p2; 146 }else{//不然就暴力删除 147 p->update(); 148 int tmp = min(dir + num - 1, p->size); 149 num -= tmp - dir + 1; 150 for (int i = 1; i <= p->size - tmp; i++) p->shu[dir + i - 1] = p->shu[tmp + i]; 151 p->size -= tmp - dir + 1; 152 p->Count(); 153 p = p->r; 154 dir = 1; 155 } 156 } 157 if (head == NULL) {head = new Node;} 158 } 159 //从pos位置开始给num个数字加上val 160 void add(int pos, int num, int val){ 161 find(pos); 162 while (num > 0){ 163 if ((dir == 1) && (num >= p->size)){ 164 //p->update(); 165 num -= p->size; 166 p->add = 1; 167 p->addn += val; 168 p = p->r; 169 }else{ 170 //打标记好像没必要update? 171 p->update();//会反转啊 172 int tmp = min(dir + num - 1, p->size); 173 num -= tmp - dir + 1; 174 for (int i = 0; i <= tmp - dir; i++) p->shu[i + dir] += val; 175 p->Count(); 176 p = p->r; 177 dir = 1; 178 } 179 } 180 } 181 int getMin(int pos, int num){ 182 int Ans = INF; 183 find(pos); 184 while (num > 0){ 185 if ((dir == 1) && (num >= p->size)){ 186 p->Count(); 187 num -= p->size; 188 Ans = min(Ans, p->Min); 189 p = p->r; 190 }else{//暴力判断 191 p->Count(); 192 int tmp = min(dir + num - 1, p->size); 193 num -= tmp - dir + 1; 194 for (int i = 0; i <= tmp - dir; i++) Ans = min(p->shu[i + dir], Ans); 195 p = p->r; 196 dir = 1; 197 } 198 } 199 return Ans; 200 } 201 //翻转 202 void Reverse(int pos, int num){ 203 Node *ap, *bp, *cp, *dp; 204 Node *p2; 205 find(pos); 206 if (p->size >= dir + num - 1){ 207 p->update(); 208 for (int i = 1; i <= (num>>1); i++) 209 swap(p->shu[dir + i - 1], p->shu[num - i + dir]); 210 //p->Count();这样不会改变Min,不用改! 211 return; 212 } 213 if (dir > 1){ 214 num -= p->size - dir + 1; 215 p2 = split(p, dir - 1); 216 ap = p2->l; 217 bp = p2; 218 p = p2->r; 219 220 }else{//不然的话dir在一个整块上, 221 ap = p->l; 222 bp = p; 223 } 224 while (num > p->size){ 225 num -= p->size; 226 p = p->r; 227 } 228 229 //最后一块切割 230 if (num != p->size){ 231 p2 = split(p, num); 232 cp = p2->l; 233 dp = p2; 234 }else{ 235 cp = p; 236 dp = p->r; 237 } 238 p = bp; 239 while (1){ 240 swap(p->l, p->r); 241 p->turn = !p->turn; 242 if (p == cp) break; 243 p = p->l; 244 } 245 //大调换 246 if (dp != NULL) dp->l = bp; 247 bp->r = dp; 248 cp->l = ap; 249 if (ap != NULL) ap->r= cp; 250 else head = cp; 251 } 252 //旋转 253 //将[a,b]和[b+1, c]调换 254 void Revolve(int a, int b, int c){ 255 if (b == c) return; 256 Node *z[3], *y[3]; 257 Node *p2; 258 int L = c - a + 1;//总长度 259 int L2 = b - a + 1;//[a,b]的长度 260 find(a); 261 int num = L2; 262 //全部在一个块内 263 if (p->size >= dir + L - 1){ 264 int tmp[SIZE], cnt = 1; 265 for (int i = dir + L2; i <= dir + L - 1; i++) tmp[cnt++] = p->shu[i]; 266 for (int i = dir; i <= dir + L2 - 1; i++) tmp[cnt++] = p->shu[i]; 267 for (int i = dir; i <= dir + L - 1; i++) p->shu[i] = tmp[i - dir + 1]; 268 return; 269 } 270 //分割第一块 271 if (dir > 1){ 272 num -= p->size - dir + 1; 273 p2 = split(p, dir - 1); 274 z[0] = p2->l; 275 y[0] = p2; 276 p = p2->r; 277 }else{ 278 z[0] = p->l; 279 y[0] = p; 280 } 281 //中间的这一块 282 //num = L2; 283 while (num > p->size){ 284 num -= p->size; 285 p = p->r; 286 } 287 int tmp = num; 288 num = L - L2; 289 if (tmp == p->size){ 290 z[1] = p; 291 y[1] = p->r; 292 p = p->r;//这里还要走 293 }else if(tmp == 0){ 294 z[1] = p->l; 295 y[1] = p; 296 }else{ 297 // num -= p->size - tmp; 298 p2 = split(p, tmp); 299 z[1] = p2->l; 300 y[1] = p2; 301 p = p2; 302 } 303 304 while (num > p->size){ 305 num -= p->size; 306 p = p->r; 307 } 308 309 if (num == p->size){ 310 z[2] = p; 311 y[2] = p->r; 312 }else if (num == 0){ 313 z[2] = p->l; 314 y[2] = p; 315 }else{ 316 p2 = split(p, num); 317 z[2] = p2->l; 318 y[2] = p2; 319 } 320 //大调换! 321 if (z[0] != NULL) z[0]->r = y[1]; 322 else head = y[1];y[1]->l = z[0]; 323 if (y[2] != NULL) y[2]->l = z[1];z[1]->r = y[2]; 324 z[2]->r = y[0]; 325 y[0]->l = z[2]; 326 } 327 void print(){ 328 Node *cur = head; 329 while (1){ 330 if (cur == NULL) break; 331 cur->update(); 332 for (int i = 1; i <= cur->size; i++) printf("%d ", cur->shu[i]); 333 cur = cur->r; 334 } 335 } 336 }A; 337 int n, data[MAXN]; 338 char str[10]; 339 340 void debug(); 341 void init(){ 342 scanf("%d", &n); 343 for (int i = 1; i <= n; i++) scanf("%d", &data[i]); 344 A.Insert(0, n, data); 345 } 346 void work(){ 347 //tot为数字总述 348 int m, tot = n; 349 scanf("%d", &m); 350 for (int i = 1; i <= m; i++){ 351 if (i == 3) 352 printf(""); 353 scanf("%s", str); 354 if (str[0] == 'A'){ 355 int l, r, x; 356 scanf("%d%d%d", &l, &r, &x); 357 if (r>= tot) A.add(l, r - l + 1, x); 358 }else if (str[0] == 'I'){ 359 int l, x; 360 scanf("%d%d", &l, &x); 361 data[1] = x; 362 A.Insert(l, 1, data); 363 tot++; 364 }else if (str[0] == 'M'){ 365 int l, r; 366 scanf("%d%d", &l, &r); 367 if (r >= tot) printf("%d\n", A.getMin(l, r - l + 1)); 368 }else if (str[0] == 'D'){ 369 int l; 370 scanf("%d", &l); 371 tot--; 372 if (l >= tot) A.Delete(l, 1); 373 }else if (!strcmp(str, "REVERSE")){ 374 int l, r; 375 scanf("%d%d", &l, &r); 376 if (l == r) continue; 377 if (r >= tot )A.Reverse(l, r - l + 1); 378 }else{ 379 int l, r, t; 380 scanf("%d%d%d", &l, &r, &t); 381 //注意t可能为- 382 int len = r - l + 1; 383 t = (t%len + len) % len; 384 if (t && r >= tot) A.Revolve(l, r - t, r); 385 } 386 } 387 } 388 void debug(){ 389 data[1] = 1; 390 data[2] = 3; 391 data[3] = 5; 392 A.Insert(0, 2, data);data[1] = 2; data[2] = 4; 393 A.Insert(2, 2, data);data[1] = 5; data[2] = 1; 394 A.Insert(4, 2, data); 395 //A.Reverse(2, 4); 396 //A.split(A.head, 1); 397 A.print(); 398 printf("\n%d", A.getMin(2, 4)); 399 } 400 401 int main(){ 402 #ifdef LOCAL 403 freopen("data.txt", "r", stdin); 404 freopen("std.txt", "w", stdout); 405 #endif 406 init(); 407 work(); 408 //debug(); 409 return 0; 410 }