【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, {A1A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:

  1. 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}
  2. 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}
  3. REVOLVE x y T: rotate sub-sequence {Ax ... AyT times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
  4. 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}
  5. DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
  6. 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 (≤ 100000).

The following n lines describe the sequence.

Then follows 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 }
View Code

 

posted @ 2015-03-11 09:11  TCtower  阅读(276)  评论(0编辑  收藏  举报