【HDU3487】【splay分裂合并】Play with Chain

Problem Description

YaoYao is fond of playing his chains. He has a chain containing n diamonds on it. Diamonds are numbered from 1 to n.
At first, the diamonds on the chain is a sequence: 1, 2, 3, …, n.
He will perform two types of operations:
CUT a b c: He will first cut down the chain from the ath diamond to the bth diamond. And then insert it after the cth diamond on the remaining chain.
For example, if n=8, the chain is: 1 2 3 4 5 6 7 8; We perform “CUT 3 5 4”, Then we first cut down 3 4 5, and the remaining chain would be: 1 2 6 7 8. Then we insert “3 4 5” into the chain before 5th diamond, the chain turns out to be: 1 2 6 7 3 4 5 8.

FLIP a b: We first cut down the chain from the ath diamond to the bth diamond. Then reverse the chain and put them back to the original position.
For example, if we perform “FLIP 2 6” on the chain: 1 2 6 7 3 4 5 8. The chain will turn out to be: 1 4 3 7 6 2 5 8

He wants to know what the chain looks like after perform m operations. Could you help him?

Input

There will be multiple test cases in a test data. 
For each test case, the first line contains two numbers: n and m (1≤n, m≤3*100000), indicating the total number of diamonds on the chain and the number of operations respectively.
Then m lines follow, each line contains one operation. The command is like this:
CUT a b c // Means a CUT operation, 1 ≤ a ≤ b ≤ n, 0≤ c ≤ n-(b-a+1).
FLIP a b    // Means a FLIP operation, 1 ≤ a < b ≤ n.
The input ends up with two negative numbers, which should not be processed as a case.

Output

For each test case, you should print a line with n numbers. The ith number is the number of the ith diamond on the chain.

Sample Input

8 2
CUT 3 5 4
FLIP 2 6
-1 -1

Sample Output

1 4 3 7 6 2 5 8

Source

2010 ACM-ICPC Multi-University Training Contest(5)——Host by BJTU

【分析】

果断被指针引用坑.......

调了一个半小时,本来想复习一下昨天的内容,结果被虐了。。

感觉pushdown和update出现的地方有些奇怪.

还有就是rotate里面的写法引用和不引用是不一样的。

昨天我两个都试了一下,今天就搞混了。。。。

  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 = 500000 + 10;
 17 const int INF = 100000000;
 18 const int SIZE = 450;
 19 const int maxnode =  0x7fffffff + 10;
 20 using namespace std;
 21 int M;
 22 struct SPLAY{
 23        struct Node{
 24               int val, size;
 25               bool turn;
 26               Node *ch[2], *parent;
 27
 28               /*Node(){//暂时不要构造函数,节约时间
 29                      val = 0;
 30                      size = 0;
 31                      turn = 0;
 32                      parent = ch[0] = ch[1] = NULL;
 33               }*/
 34               int cmp(){
 35                   if (parent->ch[0] == this) return 0;
 36                   else return 1;
 37               }
 38               //更新
 39        }*root, *nil, _nil, mem[MAXN];
 40        int tot;
 41
 42        void pushdown(Node *&t){
 43             if (t == nil) return;
 44             if (t->turn){
 45                Node *p;
 46                p = t->ch[0];
 47                t->ch[0] = t->ch[1];
 48                t->ch[1] = p;
 49
 50                if (t->ch[0] != nil) t->ch[0]->turn ^= 1;
 51                if (t->ch[1] != nil) t->ch[1]->turn ^= 1;
 52                t->turn = 0;
 53             }
 54        }
 55        void update(Node *&t){
 56             t->size = 1;
 57             t->size += t->ch[0]->size + t->ch[1]->size;
 58        }
 59        Node* NEW(int val){
 60              Node *p = &mem[tot++];
 61              p->val = val;
 62              p->size = 1;
 63              p->turn = 0;
 64              p->parent = p->ch[0] = p->ch[1] = nil;
 65              return p;
 66        }
 67        void init(){
 68             //哨兵初始化
 69             nil = &_nil;
 70             _nil.val = _nil.size = _nil.turn = 0;
 71             _nil.parent = _nil.ch[0] = _nil.ch[1] = nil;
 72
 73             tot = 0;
 74             root = NEW(INF);
 75             root->ch[1] = NEW(INF);
 76             root->ch[1]->parent  = root;
 77        }
 78        //1为右旋
 79        /*void Rotate(Node *&t, int d){
 80             Node *p = t->parent;
 81             pushdown(p);
 82             pushdown(t);
 83             pushdown(t->ch[d]);
 84             //t = p->ch[d ^ 1];这句话是废话,真正的一句一处
 85             p->ch[d ^ 1] = t->ch[d];
 86             if (t->ch[d] != nil) t->ch[d]->parent = p;
 87             t->parent = p->parent;
 88             if (p->parent != nil) p->ch[p->cmp()] = t;
 89             t->ch[d] = p;
 90             p->parent = t;
 91             update(p);//注意这里为什么只要updatep是因为旋转是在伸展中使用的,因此t的更新在splay中
 92             if (root == p) root = t;//换根
 93        }*/
 94        void Rotate(Node *t, int d){
 95             Node *p = t->parent;//t的右旋对于p来说也是右旋
 96             t = p->ch[d ^ 1];
 97             p->ch[d ^ 1] = t->ch[d];
 98             t->ch[d]->parent = p;
 99             t->ch[d] = p;
100             t->parent = p->parent;
101             //注意,这里要更新的原因在于t并不是引用
102             if (t->parent != nil){
103                if (t->parent->ch[0] == p) t->parent->ch[0] = t;
104                else if (t->parent->ch[1] == p)  t->parent->ch[1] = t;
105             }
106             p->parent = t;
107             if (t->parent == nil) root = t;
108             //不用换回去了...
109             update(p);
110             update(t);
111             //t->update();
112        }
113        void splay(Node *x, Node *y){
114             pushdown(x);
115             while (x->parent != y){
116                   if (x->parent->parent == y){
117                      Rotate(x, x->cmp() ^ 1);
118                      break;
119                   }else{
120                      Rotate(x->parent, x->parent->cmp() ^ 1);
121                      Rotate(x, x->cmp() ^ 1);
122                   }
123                   update(x);
124             }
125             update(x);//最后退出的update不要忘了
126             if (nil == y) root = x;
127        }
128        //找到第k小的数并将其伸展到y
129        void find(Node *y, int k){
130             Node *x = root;
131             while (1){
132                   //if (x == nil) break;//注意我已经在init中插入了两个数
133                   pushdown(x);
134                   int tmp = (x->ch[0]->size);
135                   if ((tmp + 1) == k) break;
136                   if (k <= tmp) x = x->ch[0];
137                   else k -= tmp + 1, x = x->ch[1];
138             }
139             pushdown(x);
140             splay(x, y);
141        }
142        //在pos位置后面插入一个数val
143        void Insert(int pos, int val){
144             find(nil, pos + 1);
145             find(root, pos + 2);//时刻注意已经插入了两个INF
146             pushdown(root);
147             pushdown(root->ch[1]);
148             Node *p = NEW(val), *t = root->ch[1];
149             //一定要拆开!!不能放在ch[1]->[0]
150             p->ch[1] = t;
151             t->parent = p;
152             root->ch[1] = p;
153             p->parent = root;
154             splay(p, nil);
155        }
156        //剪掉a,b位置的数并接到c位置后面
157        void Cut(int a, int b, int c){
158             find(nil, a);
159             find(root, b + 2);
160             pushdown(root);
161             pushdown(root->ch[1]);
162
163             Node *p = root->ch[1]->ch[0];
164             root->ch[1]->ch[0] = nil;//剪掉
165             update(root->ch[1]);///不要忘了更新
166             update(root);
167
168             find(nil, c + 1);
169             find(root, c + 2);
170             pushdown(root);
171             pushdown(root->ch[1]);
172
173             root->ch[1]->ch[0] = p;
174             p->parent = root->ch[1];
175             update(root->ch[1]);
176             update(root);
177             splay(p, nil);
178        }
179        void Reverse(int l, int r){
180             find(nil, l);
181             find(root, r + 2);
182             //print(root);
183             root->ch[1]->ch[0]->turn ^= 1;
184             Node *p = root->ch[1]->ch[0];
185             splay(p, nil);
186        }
187        void print(Node *t){
188             if (t == nil) return;
189             pushdown(t);
190             print(t->ch[0]);
191             if (t->val != INF){
192                if (M != 1) {printf("%d ", t->val);M--;}
193                else printf("%d", t->val);
194             }
195             print(t->ch[1]);
196        }
197 }A;
198 int n, m;
199
200 void init(){
201      A.init();
202      //scanf("%d%d", &n, &m);
203      for (int i = 0; i < n; i++){
204          A.Insert(i, i + 1);
205      }
206      //A.print(A.root);
207 }
208 void work(){
209      for (int i = 1; i <= m; i++){
210          char str[10];
211          scanf("%s", str);
212          if (str[0] == ‘C‘){
213             int a, b, c;
214             scanf("%d%d%d", &a, &b, &c);
215             A.Cut(a, b, c);
216          }else{
217             int l, r;
218             scanf("%d%d", &l, &r);
219             A.Reverse(l, r);
220          }
221          //A.print(A.root);
222      }
223      M = n;
224      A.print(A.root);
225 }
226
227 int main(){
228
229     while (scanf("%d%d", &n, &m)){
230           if (n == -1 && m == -1) break;
231           init();
232           //A.find(A.nil, 3);
233           //printf("%d", A.root->size);
234           work();
235           printf("\n");
236     }
237     return 0;
238 }

时间: 2024-10-12 20:32:54

【HDU3487】【splay分裂合并】Play with Chain的相关文章

【BZOJ2733】永无乡[splay启发式合并or线段树合并]

题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被这坑了. 网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 这道题似乎挺经典的(至少我看许多神犇很早就做了这道题).这道题有两种写法:并查集+(splay启发式合并or线段树合并).我写的是线段树合并,因为--splay不会打+懒得学.

BZOJ2733 永无乡【splay启发式合并】

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含

bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例,submit,1A! 哇真的舒服 调试输出懒得删了QwQ #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> #include

【BZOJ-2809】dispatching派遣 Splay + 启发式合并

2809: [Apio2012]dispatching Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2334  Solved: 1192[Submit][Status][Discuss] Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都有且仅有一个上级.为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是

线段树分裂合并

线段树分裂合并 我先接触的是线段树合并所以先讲线段树合并. 首先,用来合并的线段树必须是动态开点的.线段树合并所做的事就是合并两棵动态开点线段树的信息,对于两棵动态开点线段树,可能会存在一些公共节点,我们所要做的就是合并这些节点的信息,然后把其他节点的信息继承.理清思路之后,剩下的事就是.设初始信息的个数是\(n\),值域是\(m\),对于每一个初始信息一次这样的操作是\(\log m\)的,而每个信息只会被合并一次,所以一般的线段树合并是\(O(n \log m)\)的.非常好理解,直接上模板

Hdu3487-Play with Chain(伸展树分裂合并)

Problem Description YaoYao is fond of playing his chains. He has a chain containing n diamonds on it. Diamonds are numbered from 1 to n. At first, the diamonds on the chain is a sequence: 1, 2, 3, …, n. He will perform two types of operations: CUT a

UVA 11922 Splay区间翻转+分裂+合并

- Permutation Transformer Time Limit:2000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 11922 Appoint description:  System Crawler  (2014-11-30) Description  Permutation Transformer  Write a program to transform th

模板——伸展树 splay 实现快速分裂合并的序列

伸展操作:将treap中特定的结点旋转到根 //将序列中从左数第k个元素伸展到根,注意结点键值保存的是原序列id void splay(Node* &o, int k) { int s = o->ch[0] == NULL ? 0 : o->ch[0]->s; int d = k <= s ? 0 : (k == s+1 ? -1 : 1); if(d == 1) k -= s+1; if(d != -1) { splay(o->ch[d], k); rotate(o

Splay 支持序列分裂合并模板

//使用每个指针之前都要特别注意是否为空 #include<iostream> #include<cstring> #include<set> #include<map> #include<cmath> #include<stack> #include<queue> #include<deque> #include<list> #include<algorithm> #include&l