HDU-3487 Play with Chain Splay tee区间反转,移动

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487

  对于一个数列有两种操作:1.CUT a b c,先取出a-b区间的数,然后把它们放在取出后的第c个数后面。2.FLIP a b,把区间a-b的数反转。对于第一个操作,进行两次区间移动,第a-1个数Splay到根节点,b+1个数Splay到root的右儿子,ch[ch[root][1]][0]则表示那个区间,然后把它们除掉,然后在移动区间,把第c个数Splay到root,第c+1个数Splay到root的右儿子,再把刚才的区间加上即可。第二次操作每个节点标价一下,表示他的儿子是否反转,用懒惰操作标记延迟更新。。。

  1 //STATUS:C++_AC_578MS_6452KB
  2 #include <functional>
  3 #include <algorithm>
  4 #include <iostream>
  5 //#include <ext/rope>
  6 #include <fstream>
  7 #include <sstream>
  8 #include <iomanip>
  9 #include <numeric>
 10 #include <cstring>
 11 #include <cassert>
 12 #include <cstdio>
 13 #include <string>
 14 #include <vector>
 15 #include <bitset>
 16 #include <queue>
 17 #include <stack>
 18 #include <cmath>
 19 #include <ctime>
 20 #include <list>
 21 #include <set>
 22 #include <map>
 23 using namespace std;
 24 //using namespace __gnu_cxx;
 25 //define
 26 #define pii pair<int,int>
 27 #define mem(a,b) memset(a,b,sizeof(a))
 28 #define lson l,mid,rt<<1
 29 #define rson mid+1,r,rt<<1|1
 30 #define PI acos(-1.0)
 31 //typedef
 32 typedef __int64 LL;
 33 typedef unsigned __int64 ULL;
 34 //const
 35 const int N=300010;
 36 const int INF=0x3f3f3f3f;
 37 const int MOD=100000,STA=8000010;
 38 const LL LNF=1LL<<60;
 39 const double EPS=1e-8;
 40 const double OO=1e15;
 41 const int dx[4]={-1,0,1,0};
 42 const int dy[4]={0,1,0,-1};
 43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
 44 //Daily Use ...
 45 inline int sign(double x){return (x>EPS)-(x<-EPS);}
 46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
 47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
 48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
 49 template<class T> inline T Min(T a,T b){return a<b?a:b;}
 50 template<class T> inline T Max(T a,T b){return a>b?a:b;}
 51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
 52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
 53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
 54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
 55 //End
 56 
 57 #define Key_value ch[ch[root][1]][0]
 58 int pre[N],ch[N][2];  //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量
 59 int sz[N],st[N];   //子树规模,内存池
 60 int root,tot,top;   //根节点,根节点数量,内存池容量
 61 //题目特定数目
 62 int key[N];
 63 bool rev[N];
 64 int n,m;
 65 //debug部分copy from hh
 66 void Treaval(int x) {
 67     if(x) {
 68         Treaval(ch[x][0]);
 69         printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d rev = %2d key = %2d
",x,ch[x][0],ch[x][1],pre[x],sz[x],rev[x],key[x]);
 70         Treaval(ch[x][1]);
 71     }
 72 }
 73 void debug() {printf("%d
",root);Treaval(root);}
 74 //以上Debug
 75 //新建一个结点
 76 void NewNode(int &x,int fa,int k)
 77 {
 78     if(top)x=st[--top];
 79     else x=++tot;
 80     key[x]=k;
 81     pre[x]=fa;
 82     sz[x]=1;
 83     rev[x]=0;
 84     ch[x][0]=ch[x][1]=0;  //左右孩子为空
 85 }
 86 
 87 void Push_Up(int x)
 88 {
 89     sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
 90 }
 91 
 92 void Push_Down(int x)
 93 {
 94     if(rev[x]){
 95         rev[ch[x][0]]^=1;
 96         rev[ch[x][1]]^=1;
 97         swap(ch[x][0],ch[x][1]);
 98         rev[x]=0;
 99     }
100 }
101 //旋转,kind为1为右旋,kind为0为左旋
102 void Rotate(int x,int kind)
103 {
104     int y=pre[x],z=pre[y];
105     Push_Down(y);
106     Push_Down(x);  //先把y的标记向下传递,再把x的标记往下传递
107     //类似SBT,要把其中一个分支先给父节点
108     ch[y][!kind]=ch[x][kind];
109     pre[ch[x][kind]]=y;
110     //如果父节点不是根结点,则要和父节点的父节点连接起来
111     if(z)ch[z][ch[z][1]==y]=x;
112     pre[x]=z;
113     ch[x][kind]=y;
114     pre[y]=x;
115     Push_Up(y);  //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可
116 }
117 //Splay调整,将根为r的子树调整为goal
118 void Splay(int x,int goal)
119 {
120     int y,z,kind;
121     while(pre[x]!=goal){
122         //父节点即是目标位置,goal为0表示,父节点就是根结点
123         y=pre[x];
124         Push_Down(pre[y]);Push_Down(y);Push_Down(x);   //设计到反转操作,要先更新,然后在判断!!
125         if(pre[y]==goal){
126             Rotate(x,ch[y][0]==x);
127         }
128         else {
129             kind=ch[pre[y]][0]==y;
130             //两个方向不同,则先左旋再右旋
131             if(ch[y][kind]==x){
132                 Rotate(x,!kind);
133                 Rotate(x,kind);
134             }
135             //两个方向相同,相同方向连续两次
136             else {
137                 Rotate(y,kind);
138                 Rotate(x,kind);
139             }
140         }
141     }
142     //更新根结点
143     Push_Up(x);
144     if(goal==0)root=x;
145 }
146 
147 void RotateTo(int k,int goal)
148 {
149     int x=root;
150     Push_Down(x);
151     while(sz[ch[x][0]]!=k){
152         if(sz[ch[x][0]]>k)
153             x=ch[x][0];
154         else {
155             k-=sz[ch[x][0]]+1;
156             x=ch[x][1];
157         }
158         Push_Down(x);
159     }
160     Splay(x,goal);
161 }
162 //建树,中间结点先建立,然后分别对区间两端在左右子树建立
163 void BuildTree(int &x,int l,int r,int fa)
164 {
165     if(l>r)return;
166     int mid=(l+r)>>1;
167     NewNode(x,fa,mid);
168     BuildTree(ch[x][0],l,mid-1,x);
169     BuildTree(ch[x][1],mid+1,r,x);
170     Push_Up(x);
171 }
172 
173 void Init()
174 {
175     root=top=tot=0;
176     ch[0][0]=ch[0][1]=sz[0]=pre[0]=rev[0]=0;
177 
178     NewNode(root,0,-1);
179     NewNode(ch[root][1],root,-1);
180     BuildTree(Key_value,1,n,ch[root][1]);
181     Push_Up(ch[root][1]);
182     Push_Up(root);
183 }
184 
185 int ok;
186 void print(int u)
187 {
188     if(!u)return;
189     Push_Down(u);
190     print(ch[u][0]);
191     if(key[u]>0){
192         if(ok){printf("%d",key[u]);ok=0;}
193         else printf(" %d",key[u]);
194     }
195     print(ch[u][1]);
196 }
197 
198 void Cut(int a,int b,int c)
199 {
200     RotateTo(a-1,0);
201     RotateTo(b+1,root);
202     int s=Key_value;
203     Key_value=0;
204     Splay(ch[root][1],0);
205     RotateTo(c,0);
206     RotateTo(c+1,root);
207     Key_value=s;
208     pre[s]=ch[root][1];
209     Splay(Key_value,0);
210 }
211 
212 void Flip(int a,int b)
213 {
214     RotateTo(a-1,0);
215     RotateTo(b+1,root);
216     rev[Key_value]^=1;
217 }
218 
219 int main()
220 {
221  //   freopen("in.txt","r",stdin);
222     int i,j,a,b,c;
223     char s[10];
224     while(~scanf("%d%d",&n,&m) && (n>=0 || m>=0))
225     {
226         if(n==1){
227             printf("1
");
228             continue;
229         }
230         Init();
231         while(m--){
232             scanf("%s",s);
233             if(s[0]=='C'){
234                 scanf("%d%d%d",&a,&b,&c);
235                 Cut(a,b,c);
236             }
237             else {
238                 scanf("%d%d",&a,&b);
239                 Flip(a,b);
240             }
241         }
242         ok=1;
243         print(root);
244         putchar('
');
245     }
246     return 0;
247 }
原文地址:https://www.cnblogs.com/zhsl/p/3222649.html