[HDOJ3911]Black And White(线段树,区间合并)

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

题意:一个01串,两种操作:

0 a b:查询[a,b]内连续1的最长长度。

1 a b:翻转[a,b]内的所有数字(0变1,1变0)。

更新操作落实到具体数字,这时候不能莽直接更新数字对吧,我们要考虑翻转这个操作如何跟懒惰标记对上。让我们可以通过懒惰标记间接更新而不是直接每次更新到叶子。

我们知道一个性质:翻转偶数次相当于没有翻转,那么懒惰标记就来标记翻转次数的奇偶吧,假如是偶数次,那么不需要往下更新了。但是这样的话偶数次解决了,奇数次岂不是还要更新。我们要求连续的1的长度,需要维护一组1的长度(从左起最长、从右起最长、区间内最长),那么再对应地维护一组0的长度,反转的时候相当于这两组数字的交换,每次更新再pushup就没有问题了。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 #define lrt rt << 1
 5 #define rrt rt << 1 | 1
 6 typedef struct Node {
 7     int l, r, v;
 8     int lone, sone, rone;
 9   int lzero, szero, rzero;
10 }Node;
11 const int maxn = 100100;
12 int cmd;
13 int n, q;
14 int x[maxn];
15 Node seg[maxn<<4];
16
17 void pushUP(int rt, int len) {
18   seg[rt].lone = seg[lrt].lone; seg[rt].rone = seg[rrt].rone;
19   seg[rt].lzero = seg[lrt].lzero; seg[rt].rzero = seg[rrt].rzero;
20   if(seg[rt].lone == len-len/2) seg[rt].lone += seg[rrt].lone;
21   if(seg[rt].rone == len/2) seg[rt].rone += seg[lrt].rone;
22   if(seg[rt].lzero == len-len/2) seg[rt].lzero += seg[rrt].lzero;
23   if(seg[rt].rzero == len/2) seg[rt].rzero += seg[lrt].rzero;
24   seg[rt].sone = max(seg[lrt].sone, seg[rrt].sone);
25   seg[rt].sone = max(seg[rt].sone, seg[lrt].rone+seg[rrt].lone);
26   seg[rt].szero = max(seg[lrt].szero, seg[rrt].szero);
27   seg[rt].szero = max(seg[rt].szero, seg[lrt].rzero+seg[rrt].lzero);
28 }
29
30 void pushDOWN(int rt) {
31   if(seg[rt].v) {
32     seg[rt].v = 0;
33     seg[lrt].v = !seg[lrt].v;
34     seg[rrt].v = !seg[rrt].v;
35     swap(seg[lrt].lone, seg[lrt].lzero);
36     swap(seg[lrt].rone, seg[lrt].rzero);
37     swap(seg[lrt].sone, seg[lrt].szero);
38     swap(seg[rrt].lone, seg[rrt].lzero);
39     swap(seg[rrt].rone, seg[rrt].rzero);
40     swap(seg[rrt].sone, seg[rrt].szero);
41   }
42 }
43
44 void build(int l, int r, int rt) {
45   seg[rt].l = l; seg[rt].r = r; seg[rt].v = 0;
46   if(l == r) {
47     seg[rt].lone = seg[rt].rone = seg[rt].sone = (x[l] == 0) ? 0 : 1;
48     seg[rt].lzero = seg[rt].rzero = seg[rt].szero = (x[l] == 1) ? 0 : 1;
49     return;
50   }
51   int mid = (l + r) >> 1;
52   build(l, mid, lrt);
53   build(mid+1, r, rrt);
54   pushUP(rt, r-l+1);
55 }
56
57 void update(int L, int R, int rt) {
58   if(L <= seg[rt].l && seg[rt].r <= R) {
59     swap(seg[rt].lone, seg[rt].lzero);
60     swap(seg[rt].rone, seg[rt].rzero);
61     swap(seg[rt].sone, seg[rt].szero);
62     seg[rt].v = !seg[rt].v;
63     return;
64   }
65   pushDOWN(rt);
66   int mid = (seg[rt].l + seg[rt].r) >> 1;
67   if(L <= mid) update(L, R, lrt);
68   if(mid < R) update(L, R, rrt);
69   pushUP(rt, seg[rt].r-seg[rt].l+1);
70 }
71
72 int query(int L, int R, int rt) {
73   if(L == seg[rt].l && R == seg[rt].r) return seg[rt].sone;
74   pushDOWN(rt);
75   int mid = (seg[rt].l + seg[rt].r) >> 1;
76   if(mid >= R) return query(L, R, lrt);
77   else if(mid + 1 <= L) return query(L, R, rrt);
78   else {
79     int tmp = max(query(L, mid, lrt), query(mid+1, R, rrt));
80     tmp = max(tmp, min(seg[lrt].rone,mid-L+1)+min(seg[rrt].lone,R-mid));
81     return tmp;
82   }
83 }
84
85 int main() {
86   //freopen("in", "r", stdin);
87   int a, b;
88   while(~scanf("%d", &n)) {
89     for(int i = 1; i <= n; i++) scanf("%d", &x[i]);
90     build(1, n, 1);
91     scanf("%d", &q);
92     while(q--) {
93       scanf("%d %d %d", &cmd, &a, &b);
94       if(cmd == 0) printf("%d\n", query(a, b, 1));
95       else update(a, b, 1);
96     }
97   }
98   return 0;
99 }
时间: 2024-10-16 23:42:46

[HDOJ3911]Black And White(线段树,区间合并)的相关文章

hdu3911 Black And White(线段树区间合并)

题意:给一个由0,1组成的序列,有两种操作,一种是翻转给定区间的数(0->1,1->0),另一种是查询给定区间内由1组成的子串的最大长度.重点在区间合并和延迟标记. #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #i

HDU 3911 Black And White (线段树区间合并 + lazy标记)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3911 给你n个数0和1,m个操作: 0操作  输出l到r之间最长的连续1的个数 1操作  将l到r之间的0变1,1变0 区间合并的模版题,结构体中的lsum1表示从此区间最左端开始连续1的个数,rsum1表示从此区间最右端开始连续1的个数,sum1表示此区间连续1的个数最长是多少.lsum0,rsum0,sum0也是如此.每一次1的操作将区间内lazy标记与1异或一次,异或两次就说明操作抵消了.然后

HDU 3911 Black And White(线段树区间合并)

Problem Description There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she wan

HDU 3308 LCIS (线段树区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1

HDU 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability

poj3667 线段树 区间合并

1 //Accepted 3728 KB 1079 ms 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a document

hdu3911 线段树 区间合并

1 //Accepted 3911 750MS 9872K 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a documen

线段树 区间合并

poj3667 Hotel 区间合并入门题,照着代码打的, 题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边       2 a b:将[a,a+b-1]的房间清空思路:记录区间中最长的空房间,开三个数组,msum[rt]表示节点rt内连续的1的个数的最大值,lsum[rt]表示从节点rt左端点开始连续1的个数,rsum[rt]表示从节点rt右端点开始连续1的个数..线段树操作:update:区间替换 query:询问满足条件的最左端点 1 #include<iostream>

【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)

[BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少.1 ≤ n ≤ 105,1 ≤ m ≤ 105,1 ≤ l ≤ r ≤ n, 1 ≤ k ≤ 20 Sample Input 9 9 -8 9 -1 -1 -1 9 -8 9 3 1 1 9 1 1 1 9 2 1 4 6 3 Sample Output 17 25

HDU 3308 LCIS(最长连续上升子序列)(线段树区间合并)

题意:给你n个整数,有两种操作,U A B把第A个数变成B,Q A B查询区间[A,B]的最长连续上升序列. 思路:还是查询和更新操作,而且也是询问区间中满足条件的连续最长区间 ,所以是线段树区间合并类型的题,通法是开三棵线段树,一个记录此区间内的LCIS的最长长度,一个记录从左边第一个数开始的LCIS长度,另一个记录从右边最后一个数结尾的LCIS长度.然后试图找到父亲与儿子关系维护的递推关系式就好 本题中的递推关系是: 1. 左儿子最右边的值 < 右儿子最左边的值 lmx = (左儿子的lmx