Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 7822    Accepted Submission(s): 2347

Problem Description
lxhgww got a sequence contains n characters which are all '0's or '1's.

We have five operations here:

Change operations:

0 a b change all characters into '0's in [a , b]

1 a b change all characters into '1's in [a , b]

2 a b change all '0's into '1's and change all '1's into '0's in [a, b]

Output operations:

3 a b output the number of '1's in [a, b]

4 a b output the length of the longest continuous '1' string in [a , b]
 
Input
T(T<=10) in the first line is the case number.

Each case has two integers in the first line: n and m (1 <= n , m <= 100000).

The next line contains n characters, '0' or '1' separated by spaces.

Then m lines are the operations:

op a b: 0 <= op <= 4 , 0 <= a <= b < n.
 
Output
For each output operation , output the result.
 
Sample Input
  1. 1
  2. 10 10
  3. 0 0 0 1 1 0 1 0 1 1
  4. 1 0 2
  5. 3 0 5
  6. 2 2 2
  7. 4 0 4
  8. 0 3 6
  9. 2 3 7
  10. 4 2 8
  11. 1 0 5
  12. 0 5 6
  13. 3 3 9
 
Sample Output
  1. 5
  2. 2
  3. 6
  4. 5
 
Author
lxhgww&&shǎ崽
 
Source

【题解】

给你个01串。

有以下几种操作:

1.把[l.r]区间的所有数都置为0或1.

2.把[l,r]区间的所有数都置为其相反数.

3.求[l,r]区间内的1的个数.

4.求[l,r]区间内的最长的连续的'1'的个数.

求[l..r]区间内的1的个数,实际上就是对l..r这个区间求和.(只有0和1)

然后求l..r区间内的最长的连续的'1'的个数则需要一些技巧。

这样想。

一个区间l..r

把它分为左半部分l..m

和右半部分m+1..r

这个最长的所求序列。要么在左边。要么在右边。

要么有一部分在左边有一部分在右边。

于是我们设lx[rt]表示rt这个区间内的最长所求序列的长度;

则lx[rt] = max{lx[rt<<1],lx[rt<<1|1]};

然后对于横跨左右两边的情况。

我们需要记录lnum[rt],rnum[rt],表示这个区间最左边的数字和这个区间最右边的数字。

同时还要记录llx[rt],rlx[rt],表示从区间的最左边的一个端点数起一共有多少个连续的1,以及从区间的最右边的一个端点数起一共有多少个连续的1.

如果rnum[rt<<1] == lnum[rt<<1|1] == 1;

则lx[rt]还有多一种更新即lx[rt] = max{lx[rt],rlx[rt<<1]+llx[rt<<1|1]};

但这还远远不够我们在进行取反操作之后重新更新这些值。

想想如果我们对一个区间取反了。要怎么重新确定llx[rt],rlx[rt],lx[rt]这些值???

0->1

1->0

启发我们可以多开一个域。记录有关0的连续序列的信息

即llx[0..1][rt],rlx[0..1][rt],lx[0..1][rt];

则我们取反之后swap(llx[1][rt],llx[0][rt])swap(rlx[1][rt] , rlx[0][rt])swap(lx[1][rt] , lx[0][rt]);

即有关0的连续的信息,有关1的连续的信息同时记录下来。

sum的话就直接等于len-sum了

具体的看代码;

处理区间的时候,左右端点都递增了1,这样就是1-n了不是0到n-1

【代码】

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #define lson begin,m,rt<<1
  5. #define rson m+1,end,rt<<1|1
  6.  
  7. using namespace std;
  8.  
  9. const int MAXN = 100100;
  10.  
  11. int n, m;
  12. int llx[2][MAXN * 4], rlx[2][MAXN * 4], lx[2][MAXN * 4];
  13. int sum[MAXN * 4], qufan[MAXN * 4], fugai[MAXN * 4],lnum[MAXN*4],rnum[MAXN*4];
  14.  
  15. void push_up(int rt, int len)
  16. {
  17. sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
  18. for (int ii = 0; ii <= 1; ii++)//0和1的信息都要维护
  19. {
  20. bool flag = false;
  21. if (rnum[rt << 1] == ii && lnum[rt << 1 | 1] == ii)
  22. flag = true;
  23. lx[ii][rt] = max(lx[ii][rt << 1], lx[ii][rt << 1 | 1]);
  24. if (flag)
  25. lx[ii][rt] = max(lx[ii][rt], rlx[ii][rt << 1] + llx[ii][rt << 1 | 1]);
  26. llx[ii][rt] = llx[ii][rt << 1];
  27. if (llx[ii][rt] == (len - (len >> 1)) && flag)//如果左区间都是一样的数字
  28. llx[ii][rt] += llx[ii][rt << 1 | 1];//加上右区间的左半部分
  29. rlx[ii][rt] = rlx[ii][rt << 1 | 1];
  30. if (rlx[ii][rt] == len >> 1 && flag )
  31. rlx[ii][rt] += rlx[ii][rt << 1];
  32. }
  33. lnum[rt] = lnum[rt << 1];
  34. rnum[rt] = rnum[rt << 1 | 1];
  35. }
  36.  
  37. void build(int begin, int end, int rt)
  38. {
  39. if (begin == end)
  40. {
  41. int x;
  42. scanf("%d", &x);
  43. for (int ii = 0; ii <= 1; ii++)
  44. if (x == ii)
  45. llx[ii][rt] = rlx[ii][rt] = lx[ii][rt] = 1;
  46. else
  47. llx[ii][rt] = rlx[ii][rt] = lx[ii][rt] = 0;
  48. if (x == 0)
  49. sum[rt] = 0, lnum[rt] = 0, rnum[rt] = 0;
  50. else
  51. sum[rt] = 1,lnum[rt] =1,rnum[rt] = 1;
  52. return;
  53. }
  54. int m = (begin + end) >> 1;
  55. build(lson);
  56. build(rson);
  57. push_up(rt,end-begin+1);
  58. }
  59.  
  60. void input_data()
  61. {
  62. scanf("%d%d", &n, &m);
  63. build(1, n, 1);
  64. }
  65.  
  66. void init()//初始化
  67. {
  68. memset(fugai, 255, sizeof(fugai));
  69. memset(qufan, 0, sizeof(qufan));
  70. memset(llx, 0, sizeof(llx));
  71. memset(sum, 0, sizeof(sum));
  72. memset(rlx, 0, sizeof(rlx));
  73. memset(lx, 0, sizeof(lx));
  74. }
  75.  
  76. void tihuan(int rt, int len, int num)//把rt这个节点全部替换为num
  77. {
  78. sum[rt] = len*num;
  79. lnum[rt] = rnum[rt] = num;
  80. for (int ii = 0; ii <= 1; ii++)
  81. if (num == ii)
  82. llx[ii][rt] = rlx[ii][rt] = lx[ii][rt] = len;
  83. else
  84. llx[ii][rt] = rlx[ii][rt] = lx[ii][rt] = 0;
  85. }
  86.  
  87. void change(int rt, int len) //把rt这个区间全部取反
  88. {
  89. swap(lx[0][rt], lx[1][rt]);
  90. swap(llx[0][rt], llx[1][rt]);
  91. swap(rlx[0][rt], rlx[1][rt]);
  92. sum[rt] = len - sum[rt];
  93. lnum[rt] = 1 - lnum[rt];
  94. rnum[rt] = 1 - rnum[rt];
  95. }
  96.  
  97. void pre_change(int rt,int len)//把rt区间取反
  98. {
  99. if (fugai[rt] != -1)
  100. {
  101. fugai[rt] = 1 - fugai[rt];
  102. tihuan(rt, len, fugai[rt]);
  103. }
  104. else
  105. {
  106. qufan[rt] = 1 - qufan[rt];
  107. change(rt, len);
  108. }
  109. }
  110.  
  111. void push_down(int rt, int len)
  112. {
  113. if (fugai[rt] != -1)
  114. {
  115. fugai[rt << 1] = fugai[rt << 1 | 1] = fugai[rt];
  116. qufan[rt << 1] = qufan[rt << 1 | 1] = 0;
  117. tihuan(rt << 1, len - (len >> 1), fugai[rt]);
  118. tihuan(rt << 1 | 1, len >> 1, fugai[rt]);
  119. fugai[rt] = -1;
  120. }
  121. else //如果有覆盖操作就不可能有取反操作(想想为什么)
  122. if (qufan[rt]!=0)
  123. {
  124. pre_change(rt << 1, len - (len >> 1));
  125. pre_change(rt << 1 | 1, len >> 1);
  126. qufan[rt] = 0;
  127. }
  128. }
  129.  
  130. void up_data(int op, int l, int r, int begin, int end, int rt)
  131. {
  132. if (l <= begin && end <= r)
  133. {
  134. if (op <= 1) //覆盖操作
  135. {
  136. fugai[rt] = op;
  137. qufan[rt] = 0;
  138. tihuan(rt, end - begin + 1,op);
  139. }
  140. else //取反操作
  141. pre_change(rt, end - begin + 1);
  142. return;
  143. }
  144. push_down(rt, end - begin + 1);
  145. int m = (begin + end) >> 1;
  146. if (l <= m)
  147. up_data(op, l, r, lson);
  148. if (m < r)
  149. up_data(op, l, r, rson);
  150. push_up(rt, end - begin + 1);
  151. }
  152.  
  153. int query_sum(int l, int r, int begin, int end, int rt)//求和
  154. {
  155. if (l <= begin && end <= r)
  156. return sum[rt];
  157. int dd = 0;
  158. push_down(rt,end-begin+1);
  159. int m = (begin + end) >> 1;
  160. if (l <= m)
  161. dd += query_sum(l, r, lson);
  162. if (m < r)
  163. dd += query_sum(l, r, rson);
  164. return dd;
  165. }
  166.  
  167. int query_lx(int l, int r, int begin, int end, int rt)//寻找最长连续1
  168. {
  169. if (l <= begin && end <= r)
  170. return lx[1][rt];
  171. push_down(rt, end - begin + 1);
  172. int dd = 0;
  173. int m = (begin + end) >> 1;
  174. bool flag1 = false, flag2 = false;
  175. if (l <= m)
  176. {
  177. dd = max(dd, query_lx(l, r, lson));
  178. flag1 = true;
  179. }
  180. if (m < r)
  181. {
  182. dd = max(dd, query_lx(l, r, rson));
  183. flag2 = true;
  184. }
  185. //在左边,在右边,横跨中间
  186. if (flag1 && flag2 && rnum[rt << 1] == 1 && lnum[rt << 1 | 1] == 1)
  187. {
  188. int temp1 = min(m - l + 1, rlx[1][rt << 1]);
  189. int temp2 = min(r - m, llx[1][rt << 1 | 1]);
  190. dd = max(dd, temp1 + temp2);
  191. }
  192. return dd;
  193. }
  194.  
  195. void output_ans()
  196. {
  197. for (int i = 1; i <= m; i++)
  198. {
  199. int op, x, y;
  200. scanf("%d%d%d", &op, &x, &y);
  201. x++; y++;
  202. if (op <= 2)
  203. up_data(op, x, y, 1, n, 1);
  204. else
  205. if (op == 3)
  206. printf("%d\n", query_sum(x, y, 1, n, 1));
  207. else
  208. if (op == 4)
  209. printf("%d\n", query_lx(x, y, 1, n, 1));
  210. }
  211. }
  212.  
  213. int main()
  214. {
  215. // freopen("F:\\rush.txt", "r", stdin);
  216. //freopen("F:\\rush_out.txt", "w", stdut);
  217. int t;
  218. scanf("%d", &t);
  219. while (t--)
  220. {
  221. init();
  222. input_data();
  223. output_ans();
  224. }
  225. return 0;
  226. }

【30.01%】【hdu 3397】Sequence operation的更多相关文章

  1. 【改革春风吹满地 HDU - 2036 】【计算几何-----利用叉积计算多边形的面积】

    利用叉积计算多边形的面积 我们都知道计算三角形的面积时可以用两个邻边对应向量积(叉积)的绝对值的一半表示,那么同样,对于多边形,我们可以以多边形上的一个点为源点,作过该点并且过多边形其他点中的某一个的 ...

  2. 【黑金教程笔记之002】【建模篇】【Lab 01 永远的流水灯】—笔记&勘误

    学习并行操作的思想. 勘误001: Page 17,模块图下方,“扫描频配置定为100Hz”应为10Hz. 勘误002: Page 17,最后一行 “10ms”应为100ms:“2.5ms”应为25m ...

  3. 【转】从外行的视角尝试讲解为什么这回丰田栽了【全文完】【v1.01】

    转自:http://club.tgfcer.com/thread-6817371-1-1.html  [第一部分]背景简介 前几年闹得沸沸扬扬的丰田刹不住事件最近又有新进展.十月底俄克拉荷马的一次庭审 ...

  4. hdu 动态规划(46道题目)倾情奉献~ 【只提供思路与状态转移方程】(转)

    HDU 动态规划(46道题目)倾情奉献~ [只提供思路与状态转移方程] Robberies http://acm.hdu.edu.cn/showproblem.php?pid=2955      背包 ...

  5. zw版【转发·台湾nvp系列Delphi例程】HALCON HWindowX 01

    zw版[转发·台湾nvp系列Delphi例程]HALCON HWindowX 01 procedure TForm1.Button1Click(Sender: TObject);var img : H ...

  6. 【HDU 2255】奔小康赚大钱 (最佳二分匹配KM算法)

    奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  7. 【二分】【最长上升子序列】HDU 5489 Removed Interval (2015 ACM/ICPC Asia Regional Hefei Online)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5489 题目大意: 一个N(N<=100000)个数的序列,要从中去掉相邻的L个数(去掉整个区间 ...

  8. 【贪心】【模拟】HDU 5491 The Next (2015 ACM/ICPC Asia Regional Hefei Online)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5491 题目大意: 一个数D(0<=D<231),求比D大的第一个满足:二进制下1个个数在 ...

  9. 【动态规划】【二分】【最长上升子序列】HDU 5773 The All-purpose Zero

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5773 题目大意: T组数据,n个数(n<=100000),求最长上升子序列长度(0可以替代任何 ...

随机推荐

  1. mysql存储过程小解

    mysql 存储过程 1.创建语法 delimiter $$ --$$表示改变默认的分隔符,代表以下为存储过程,不然会以SQL的方式执行 drop procedure if exists pro_na ...

  2. AlertDialog提示对话框练习

    闲来无事,就练习了下AlertDialog对话框. 首先写了三个button,分别打开一般对话框,单选列表对话框和复选对话框. xml代码 <LinearLayout xmlns:android ...

  3. 洛谷 P2146 [NOI2015]软件包管理器 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 输出样例#1: 输入样例#2: 输出样例#2: 说明 说明 思路 AC代码 总结 题面 题目链接 P ...

  4. hdu1080 LCS变形

    dp[i][j]表示配对的最大值. dp[i-1][j]表示s1[i-1]与'-'配对. dp[i][j-1]表示s2[j-1]与'-'配对. dp[i-1][j-1]表示s1[i-1]与s2[j-1 ...

  5. python 使用异常代替返回状态码

  6. 对The Curse of Dimensionality(维度灾难)的理解

    一个特性:低维(特征少)转向高维的过程中,样本会变的稀疏(可以有两种理解方式:1.样本数目不变,样本彼此之间距离增大.2.样本密度不变,所需的样本数目指数倍增长). 高维度带来的影响: 1.变得可分. ...

  7. ADO.NET sqlHelper类(DBHelper类)

    1.配置文件 <connectionStrings> <add name="constr" connectionString="Data Source= ...

  8. QT 建立信号和槽的联系(事件处理)

    Qt中事件处理机制叫做“信号”和“槽”signal &slot. 其模型为: 对象a中有一个信号signal:XXX(代表一个事件) 对象b中有一个槽slot:YYY(事件处理函数) 用con ...

  9. 归并排序及应用 (nyoj 117 求逆序数)

    求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5   描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中 ...

  10. 浏览器间CSS样式兼容问题

    1.display:table居中显示 在chrome和safari浏览器上兼容问题 2.滤镜 在chrome浏览器中能正常显示,在360浏览器中不能正常显示 3.省略号问题 对于一行显示,基本上对所 ...