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异或一次,异或两次就说明操作抵消了。然后就是细心点就好了。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 using namespace std;
  5 const int MAXN = 1e5 + 5;
  6 struct SegTree {
  7     int l , r , lazy;
  8     int lsum1 , rsum1 , sum1;
  9     int lsum0 , rsum0 , sum0;
 10 }T[MAXN << 2];
 11 int a[MAXN];
 12
 13 void Pushdown(int p) {
 14     if(T[p].lazy) {
 15         int ls = p << 1 , rs = (p << 1)|1;
 16         T[ls].lazy ^= T[p].lazy;
 17         T[rs].lazy ^= T[p].lazy;
 18         int temp = T[ls].lsum1;
 19         T[ls].lsum1 = T[ls].lsum0;
 20         T[ls].lsum0 = temp;
 21         temp = T[ls].rsum1;
 22         T[ls].rsum1 = T[ls].rsum0;
 23         T[ls].rsum0 = temp;
 24         temp = T[ls].sum1;
 25         T[ls].sum1 = T[ls].sum0;
 26         T[ls].sum0 = temp;
 27
 28         temp = T[rs].lsum1;
 29         T[rs].lsum1 = T[rs].lsum0;
 30         T[rs].lsum0 = temp;
 31         temp = T[rs].rsum1;
 32         T[rs].rsum1 = T[rs].rsum0;
 33         T[rs].rsum0 = temp;
 34         temp = T[rs].sum1;
 35         T[rs].sum1 = T[rs].sum0;
 36         T[rs].sum0 = temp;
 37
 38         T[p].lazy = 0;
 39     }
 40 }
 41
 42 void Pushup(int p) {
 43     T[p].lsum1 = T[p << 1].lsum1 , T[p].lsum0 = T[p << 1].lsum0;
 44     T[p].rsum1 = T[(p << 1)|1].rsum1 , T[p].rsum0 = T[(p << 1)|1].rsum0;
 45     if(T[p].lsum1 == T[p << 1].r - T[p << 1].l + 1)
 46         T[p].lsum1 += T[(p << 1)|1].lsum1;
 47     if(T[p].rsum1 == T[(p << 1)|1].r - T[(p << 1)|1].l + 1)
 48         T[p].rsum1 += T[p << 1].rsum1;
 49     if(T[p].lsum0 == T[p << 1].r - T[p << 1].l + 1)
 50         T[p].lsum0 += T[(p << 1)|1].lsum0;
 51     if(T[p].rsum0 == T[(p << 1)|1].r - T[(p << 1)|1].l + 1)
 52         T[p].rsum0 += T[p << 1].rsum0;
 53     T[p].sum1 = max(T[p << 1].sum1 , max(T[(p << 1)|1].sum1 , T[p << 1].rsum1 + T[(p << 1)|1].lsum1));
 54     T[p].sum0 = max(T[p << 1].sum0 , max(T[(p << 1)|1].sum0 , T[p << 1].rsum0 + T[(p << 1)|1].lsum0));
 55 }
 56
 57 void build(int p , int l , int r) {
 58     int mid = (l + r) >> 1;
 59     T[p].lazy = 0;
 60     T[p].l = l , T[p].r = r;
 61     if(l == r) {
 62         scanf("%d" , a + l);
 63         T[p].sum1 = T[p].lsum1 = T[p].rsum1 = a[l] ? 1 : 0;
 64         T[p].sum0 = T[p].lsum0 = T[p].rsum0 = a[l] ? 0 : 1;
 65         return ;
 66     }
 67     build(p << 1 , l , mid);
 68     build((p << 1)|1 , mid + 1 , r);
 69     Pushup(p);
 70 }
 71
 72 void updata(int p , int l , int r , int flag) {
 73     int mid = (T[p].l + T[p].r) >> 1;
 74     if(T[p].l == l && T[p].r == r) {
 75         T[p].lazy ^= flag;
 76         int temp = T[p].lsum1;
 77         T[p].lsum1 = T[p].lsum0;
 78         T[p].lsum0 = temp;
 79         temp = T[p].rsum1;
 80         T[p].rsum1 = T[p].rsum0;
 81         T[p].rsum0 = temp;
 82         temp = T[p].sum1;
 83         T[p].sum1 = T[p].sum0;
 84         T[p].sum0 = temp;
 85         return ;
 86     }
 87     Pushdown(p);
 88     if(r <= mid) {
 89         updata(p << 1 , l , r , flag);
 90     }
 91     else if(l > mid) {
 92         updata((p << 1)|1 , l , r , flag);
 93     }
 94     else {
 95         updata(p << 1 , l , mid , flag);
 96         updata((p << 1)|1 , mid + 1 , r , flag);
 97     }
 98     Pushup(p);
 99 }
100
101 int query(int p , int l , int r) {
102     int mid = (T[p].l + T[p].r) >> 1;
103     if(T[p].l == l && T[p].r == r) {
104         return T[p].sum1;
105     }
106     Pushdown(p);
107     if(r <= mid) {
108         return query(p << 1 , l , r);
109     }
110     else if(l > mid) {
111         return query((p << 1)|1 , l , r);
112     }
113     else {
114         return max( min(T[p << 1].rsum1 , mid - l + 1)+min(T[(p << 1)|1].lsum1 , r - mid) , //mid在l和r之间
115          max( query(p << 1 , l , mid) , query((p << 1)|1 , mid + 1 , r)) );
116     }
117 }
118
119 int main()
120 {
121     int n , m , choose , u , v;
122     while(~scanf("%d" , &n)) {
123         build(1 , 1 , n);
124         scanf("%d" , &m);
125         while(m--) {
126             scanf("%d %d %d" , &choose , &u , &v);
127             if(choose) {
128                 updata(1 , u , v , 1);
129             }
130             else {
131                 printf("%d\n" , query(1 , u , v));
132             }
133         }
134     }
135     return 0;
136 }
时间: 2024-10-10 03:49:21

HDU 3911 Black And White (线段树区间合并 + lazy标记)的相关文章

hdu 3911 Black And White(线段树)

题目连接:hdu 3911 Black And White 题目大意:给定一个序列,然后有M次操作: 0 l r:表示询问l,r中最大连续1的个数 1 l r:表示将l,r区间上的数取反 解题思路:线段树的一种题型,区间合并,因为有一个取反的操作,所以对于每个节点要维护6个值,包括连续0,1最长序列的长度,左边和右边的最长连续长度.需要注意的是,如果询问的区间最大值是从R[lson] + L[rson]来到,要判断是否比长度大于r - l + 1.一开始没注意,所以WA了,上网搜了下别人的题解,

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 2871 Memory Control(线段树&#183;区间合并&#183;Vector)

题意  模拟内存申请  有n个内存单元  有以下4种操作 Reset  将n个内存单元全部清空 New x  申请一个长度为x的连续内存块  申请成功就输出左端 Free x  将x所在的内存块空间释放  释放成功输出释放的内存始末位置 Get x  输出第x个内存块的起始位置 Reset 和 New 都是基本的区间合并知识  比较简单  Free和Get需要知道内层块的位置  所以我们在New的时候要将申请的内存块的始末位置都存起来  两个内层块不会相交  这样就能通过二分找到需要的内层块了

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 3397 Sequence operation,线段树+区间合并。

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 chang

线段树区间修改 lazy标记 大法

#include <cstdio> #include <cstring> #define maxn 100000 + 10 #define Lson L, mid, rt<<1 #define Rson mid+1, R, rt<<1|1 struct Node { int sum, lazy; } T[maxn<<2]; void PushUp(int rt) { T[rt].sum = T[rt<<1].sum + T[rt<

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

POJ 3667(线段树区间合并)

http://poj.org/problem?id=3667 题意:两个操作 : 1 选出靠左的长度为a的区间. 2 把从 a到a+b的区间清空. 线段树区间合并+lazy // by caonima // hehe #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cmath> using namespace std; co

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