【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

 

你可能感兴趣的:(super)