HDU3487(splay区间翻转+区间切割)

题意:开始有一个1,2,3,。。。n的序列,进行m次操作,cut a b c将区间[a,b]取出得到新序列,将区间插入到新序列第c个元素之后。filp a b 将区间a,b翻转,输出最终的序列。

思路:对于cut操作我们需要先提取出区间[a,b]然后,先暂时分裂出去,然后以c为边界分裂左右两部分,然后合并左边的和区间[a,b],将最大的旋转至根,然后和右边的合并。对于filp操作,我们可以使用lazy标记,先不翻转,需要的时候再翻转,代码如下

[cpp] view plaincopy

  1. /*************************************************************************
  2. > File Name: A.cpp
  3. > Author: acvcla
  4. > QQ:
  5. > Mail: [email protected]
  6. > Created Time: 2014年11月17日 星期一 23时34分13秒
  7. ************************************************************************/
  8. #include<iostream>
  9. #include<algorithm>
  10. #include<cstdio>
  11. #include<vector>
  12. #include<cstring>
  13. #include<map>
  14. #include<queue>
  15. #include<stack>
  16. #include<string>
  17. #include<cstdlib>
  18. #include<ctime>
  19. #include<set>
  20. #include<math.h>
  21. using namespace std;
  22. typedef long long LL;
  23. typedef pair<int,int>pii;
  24. const int maxn = 3e5 + 10;
  25. #define rep(i,a,b) for(int i=(a);i<=(b);i++)
  26. #define pb push_back
  27. int siz[maxn],rev[maxn],pre[maxn],ch[maxn][2],key[maxn],ans[maxn];
  28. int tot,root,n;
  29. inline void newnode(int &x,int fa,int k){
  30. x=++tot;
  31. pre[x]=fa;
  32. siz[x]=1;
  33. key[x]=k;
  34. ch[x][0]=ch[x][1]=rev[x]=0;
  35. }
  36. inline void Modify(int x){
  37. if(!x)return;
  38. rev[x]^=1;
  39. }
  40. inline void push_down(int x){
  41. if(x&&rev[x]){
  42. swap(ch[x][0],ch[x][1]);
  43. Modify(ch[x][0]);
  44. Modify(ch[x][1]);
  45. Modify(x);
  46. }
  47. }
  48. inline void push_up(int x){
  49. if(!x)return ;
  50. siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
  51. }
  52. void built(int &x,int L,int R,int fa){
  53. if(L>R)return;
  54. int M=(L+R)>>1;
  55. newnode(x,fa,M);
  56. built(ch[x][0],L,M-1,x);
  57. built(ch[x][1],M+1,R,x);
  58. push_up(x);
  59. }
  60. void Rotate(int x,int kind){
  61. int y=pre[x];
  62. push_down(y);
  63. push_down(x);
  64. ch[y][!kind]=ch[x][kind];
  65. pre[ch[x][kind]]=y;
  66. ch[x][kind]=y;
  67. if(pre[y])ch[pre[y]][ch[pre[y]][1]==y]=x;
  68. pre[x]=pre[y];
  69. pre[y]=x;
  70. push_up(y);
  71. push_up(x);
  72. }
  73. void Splay(int x,int goal){
  74. while(pre[x]!=goal){
  75. if(pre[pre[x]]==goal){
  76. Rotate(x,ch[pre[x]][0]==x);
  77. }else{
  78. int y=pre[x];
  79. int kind=(ch[pre[y]][0]==y);
  80. if(ch[y][kind]==x){
  81. Rotate(x,!kind);
  82. Rotate(x,kind);
  83. }else{
  84. Rotate(y,kind);
  85. Rotate(x,kind);
  86. }
  87. }
  88. }
  89. if(goal==0)root=x;
  90. }
  91. int Get_kth(int x,int k){
  92. push_down(x);
  93. int tz=siz[ch[x][0]]+1;
  94. if(tz==k)return x;
  95. if(tz>k)return Get_kth(ch[x][0],k);
  96. return Get_kth(ch[x][1],k-tz);
  97. }
  98. void init(int n){
  99. root=tot=siz[0]=pre[0]=ch[0][0]=ch[0][1]=rev[0]=0;
  100. newnode(root,0,-1);
  101. newnode(ch[root][1],root,n+1);
  102. built(ch[ch[root][1]][0],1,n,ch[root][1]);
  103. push_up(ch[root][1]);
  104. push_up(root);
  105. }
  106. int Get_max(int x){
  107. push_down(x);
  108. while(ch[x][1]){
  109. x=ch[x][1];
  110. push_down(x);
  111. }
  112. return x;
  113. }
  114. void merge(int root1,int root2)/*root2接到root1右子树,要求root1无右子树*/
  115. {
  116. ch[root1][1]=root2;
  117. pre[root2]=root1;
  118. }
  119. int __;
  120. void travel(int x){
  121. if(!x)return;
  122. push_down(x);
  123. travel(ch[x][0]);
  124. ans[__++]=key[x];
  125. travel(ch[x][1]);
  126. }
  127. int main(){
  128. int n,m;
  129. while(~scanf("%d%d",&n,&m)){
  130. if(n<0&&m<0)return 0;
  131. init(n);
  132. char op[10];
  133. int L,R,C;
  134. while(m--){
  135. scanf("%s%d%d",op,&L,&R);
  136. if(op[0]==‘F‘){
  137. Splay(Get_kth(root,L),0);
  138. Splay(Get_kth(root,R+2),root);
  139. Modify(ch[ch[root][1]][0]);
  140. }else{
  141. scanf("%d",&C);
  142. Splay(Get_kth(root,L),0);
  143. Splay(Get_kth(root,R+2),root);
  144. int root1=ch[ch[root][1]][0];/*删除区间[L,R]*/
  145. ch[ch[root][1]][0]=0;
  146. push_up(ch[root][1]);
  147. push_up(root);
  148. Splay(Get_kth(root,C+1),0);/*先分裂区间C两边,插入区间[L,R],然后合并*/
  149. int root2=ch[root][1];
  150. merge(root,root1);
  151. push_up(root);
  152. Splay(Get_max(root),0);
  153. merge(root,root2);
  154. push_up(root);
  155. }
  156. }
  157. __=0;
  158. travel(root);
  159. rep(i,1,n)printf("%d%c",ans[i],i==n?‘\n‘:‘ ‘);
  160. }
  161. return 0;
  162. }
时间: 2024-08-26 19:38:37

HDU3487(splay区间翻转+区间切割)的相关文章

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

WIKIOI 3243 区间翻转

3243 区间翻转 题目描述 Description 给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列 输入描述 Input Description 第一行一个数N,下一行N个数表示原始序列,在下一行一个数M表示M次翻转,之后的M行每行两个数L,R表示将区间[L,R]翻转. 输出描述 Output Description 一行N个数 , 表示最终序列. 样例输入 Sample Input 4 1 2 3 4 2 1 2 3 4 样例输出 Sample Outp

区间翻转

时间限制: 1 s空间限制: 256000 KB题目等级 : 钻石 Diamond 题目描述 Description 给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列 输入描述 Input Description 第一行一个数N,下一行N个数表示原始序列,在下一行一个数M表示M次翻转,之后的M行每行两个数L,R表示将区间[L,R]翻转. 输出描述 Output Description 一行N个数 , 表示最终序列. 样例输入 Sample Input 4 1

3243 区间翻转

3243 区间翻转 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列 输入描述 Input Description 第一行一个数N,下一行N个数表示原始序列,在下一行一个数M表示M次翻转,之后的M行每行两个数L,R表示将区间[L,R]翻转. 输出描述 Output Description 一行N个数 , 表示最终序列. 样例输入 Sa

splay:优雅的区间暴力!

万年不更的blog主更新啦!主要是最近实在忙,好不容易才从划水做题的时间中抽出一段时间来写这篇blog 首先声明:这篇blog写的肯定会很基础...因为身为一个蒟蒻深知在茫茫大海中找到一个自己完全能够看懂的blog有多么的难..(说多了都是泪.)所以当然希望所有初学者都能看懂这篇博文啦~ 说实话在学这个算法之前有跟强大的巨神zxyer学过treap和fhq_treap,所以对平衡树有一定的了解.当然都是理论阶段,虽然都打过一两题,但是忘得快..所以几乎等于没打. 认真重学了一遍平衡树(尤其是sp

HDU 3911 Black and White (线段树,区间翻转)

  [题目地址] vjudge HDU [题目大意] 海滩上有一堆石头. 石头的颜色是白色或黑色. 小肥羊拥有魔术刷,她可以改变连续石的颜色,从黑变白,从白变黑. 小肥羊非常喜欢黑色,因此她想知道范围[i,j]中连续的黑色石头的最长时间. 有多种情况,每种情况的第一行是整数n(1 <= n <= 10 ^ 5),后跟n个整数1或0(1表示黑石头,0表示白石头),然后是整数 M(1 <= M <= 10 ^ 5)后跟M个运算,格式为xij(x = 0或1),x = 1表示更改范围[i

HDU 3397 Sequence operation(区间合并 + 区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给定n个数,由0,1构成.共有5种操作.每个操作输入3个数,op,a,b. op == 0,将区间[a,b]赋值为0: op == 1,将区间[a,b]赋值为1: op == 2,将区间[a,b]内的01反转: op == 3,查询区间[a,b]中1的个数: op == 4,查询区间[a,b]中连续1的最大长度: 思路:区间合并 + 区间更新.每个结点存7个数: 区间内1的个数c1. 从

[用CDQ分治解决区间加&amp;区间求和]【习作】

[前言] 作为一个什么数据结构都不会只会CDQ分治和分块的蒟蒻,面对区间加&区间求和这么难的问题,怎么可能会写线段树呢 于是,用CDQ分治解决区间加&区间求和这篇习作应运而生 [Part.I]区间加&区间求和的数据结构做法 [一]线段树 裸题... 1141ms #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include

区间选点+区间覆盖

区间选点+区间覆盖 区间选点问题(选择最少的点,使得每个区间都至少有k个点) 将这些区间[l,r]先按照r从小到大排序,再按照l从大到小排序.选点尽量选择靠近右边界的点.然后按照这个排序后的区间进行遍历,用一个变量来存放遍历过程中上个区间的右边界,然后碰到一个新的区间的时候需要分两种情况讨论:1.这个区间和上个区间有相交的部分,那么就需要判断一下上次选择的点有多少在这个区间内,这些点满足要求吗?不满足的话还需要在这个区间内选点2.这个区间和上个区间没有交集,那么这个区间就需要选点. 上述策略可以