题目链接: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就没有问题了。

 #include <bits/stdc++.h>
using namespace std; #define lrt rt << 1
#define rrt rt << 1 | 1
typedef struct Node {
int l, r, v;
int lone, sone, rone;
int lzero, szero, rzero;
}Node;
const int maxn = ;
int cmd;
int n, q;
int x[maxn];
Node seg[maxn<<]; void pushUP(int rt, int len) {
seg[rt].lone = seg[lrt].lone; seg[rt].rone = seg[rrt].rone;
seg[rt].lzero = seg[lrt].lzero; seg[rt].rzero = seg[rrt].rzero;
if(seg[rt].lone == len-len/) seg[rt].lone += seg[rrt].lone;
if(seg[rt].rone == len/) seg[rt].rone += seg[lrt].rone;
if(seg[rt].lzero == len-len/) seg[rt].lzero += seg[rrt].lzero;
if(seg[rt].rzero == len/) seg[rt].rzero += seg[lrt].rzero;
seg[rt].sone = max(seg[lrt].sone, seg[rrt].sone);
seg[rt].sone = max(seg[rt].sone, seg[lrt].rone+seg[rrt].lone);
seg[rt].szero = max(seg[lrt].szero, seg[rrt].szero);
seg[rt].szero = max(seg[rt].szero, seg[lrt].rzero+seg[rrt].lzero);
} void pushDOWN(int rt) {
if(seg[rt].v) {
seg[rt].v = ;
seg[lrt].v = !seg[lrt].v;
seg[rrt].v = !seg[rrt].v;
swap(seg[lrt].lone, seg[lrt].lzero);
swap(seg[lrt].rone, seg[lrt].rzero);
swap(seg[lrt].sone, seg[lrt].szero);
swap(seg[rrt].lone, seg[rrt].lzero);
swap(seg[rrt].rone, seg[rrt].rzero);
swap(seg[rrt].sone, seg[rrt].szero);
}
} void build(int l, int r, int rt) {
seg[rt].l = l; seg[rt].r = r; seg[rt].v = ;
if(l == r) {
seg[rt].lone = seg[rt].rone = seg[rt].sone = (x[l] == ) ? : ;
seg[rt].lzero = seg[rt].rzero = seg[rt].szero = (x[l] == ) ? : ;
return;
}
int mid = (l + r) >> ;
build(l, mid, lrt);
build(mid+, r, rrt);
pushUP(rt, r-l+);
} void update(int L, int R, int rt) {
if(L <= seg[rt].l && seg[rt].r <= R) {
swap(seg[rt].lone, seg[rt].lzero);
swap(seg[rt].rone, seg[rt].rzero);
swap(seg[rt].sone, seg[rt].szero);
seg[rt].v = !seg[rt].v;
return;
}
pushDOWN(rt);
int mid = (seg[rt].l + seg[rt].r) >> ;
if(L <= mid) update(L, R, lrt);
if(mid < R) update(L, R, rrt);
pushUP(rt, seg[rt].r-seg[rt].l+);
} int query(int L, int R, int rt) {
if(L == seg[rt].l && R == seg[rt].r) return seg[rt].sone;
pushDOWN(rt);
int mid = (seg[rt].l + seg[rt].r) >> ;
if(mid >= R) return query(L, R, lrt);
else if(mid + <= L) return query(L, R, rrt);
else {
int tmp = max(query(L, mid, lrt), query(mid+, R, rrt));
tmp = max(tmp, min(seg[lrt].rone,mid-L+)+min(seg[rrt].lone,R-mid));
return tmp;
}
} int main() {
//freopen("in", "r", stdin);
int a, b;
while(~scanf("%d", &n)) {
for(int i = ; i <= n; i++) scanf("%d", &x[i]);
build(, n, );
scanf("%d", &q);
while(q--) {
scanf("%d %d %d", &cmd, &a, &b);
if(cmd == ) printf("%d\n", query(a, b, ));
else update(a, b, );
}
}
return ;
}

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

  1. 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之间 ...

  2. HDU 3911 Black And White(线段树区间合并+lazy操作)

    开始以为是水题,结果...... 给你一些只有两种颜色的石头,0为白色,1为黑色. 然后两个操作: 1 l r 将[ l , r ]内的颜色取反 0 l r 计算[ l , r ]内最长连续黑色石头的 ...

  3. hdu 3911 Black And White (线段树 区间合并)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3911 题意: 给你一段01序列,有两个操作: 1.区间异或,2.询问区间最长的连续的1得长度 思路: ...

  4. POJ 3667 Hotel(线段树 区间合并)

    Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...

  5. HDU 3911 线段树区间合并、异或取反操作

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911 线段树区间合并的题目,解释一下代码中声明数组的作用: m1是区间内连续1的最长长度,m0是区间内连续 ...

  6. HYSBZ 1858 线段树 区间合并

    //Accepted 14560 KB 1532 ms //线段树 区间合并 /* 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[ ...

  7. poj3667 线段树 区间合并

    //Accepted 3728 KB 1079 ms //线段树 区间合并 #include <cstdio> #include <cstring> #include < ...

  8. hdu3911 线段树 区间合并

    //Accepted 3911 750MS 9872K //线段树 区间合并 #include <cstdio> #include <cstring> #include < ...

  9. 线段树(区间合并) POJ 3667 Hotel

    题目传送门 /* 题意:输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边 输入 2 a b:将[a,a+b-1]的房间清空 线段树(区间合并):lsum[]统计从左端点起最长连续空房间 ...

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

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[ ...

随机推荐

  1. 修改linux下mysql目录权限

    1.进入当前目录:例cd /srun3/mysql 2.修改权用户限 chown -R mysql ipt_authd_remote(表示给ipt_authd_remotemysql权限) 3.修改用 ...

  2. OpenGL笔试题

    简述FrameBuffer,RenderBuffer,Depth Buffer,Framebuffer attachment,Stencil buffer的关系 简述利用OpenGL执行图像叠加(大P ...

  3. scala泛型

    package com.ming.test /** * scala泛型 * 类型参数测试 */ object TypeParamsTest { //泛型函数 def getMiddle[T](a:Ar ...

  4. iOS 学习笔记 七 (2015.03.29)code snippet操作

    1.code snippet 备份路径:~/Library/Developer/Xcode/UserData/CodeSnippets/

  5. Google 开发新的开源系统 Fuchsia

    google 最新os 下载 https://github.com/fuchsia-mirror/magenta 本文转自:http://www.oschina.net/news/76094/goog ...

  6. grads 用arcgis分析站点的网格

    第一步,用工具创建渔网(要素类) 第二步:将站点excel导入,生成点要素 站点excle,点击上面节点导出数据即可. 第三步,叠加在一起,找网格编号.

  7. Java中如何在另一个类里面使用运行类中的对象,举例说明了一下。

    package 计时器; import java.util.Timer; import java.util.TimerTask; /* * 主要是想在另一个类里面,使用该类的对象,如何使用呢?如何传递 ...

  8. 【jQuery UI 1.8 The User Interface Library for jQuery】.学习笔记.7.Slider控件

    默认slider的安装启用 为slider自定义风格 修改配置选项 创建一个垂直的slider 设置最大最小值,和默认值 启用多个 手柄 和 范围 slider内置的回调事件 slider的方法 这个 ...

  9. oracle 日期问题

    共三部分: 第一部分:oracle sql日期比较: http://www.cnblogs.com/sopost/archive/2011/12/03/2275078.html 第二部分:Oracle ...

  10. mac下多个php版本快速切换的方法是怎么样

    一.使用brew安装php多版本方法# brew install php56# brew install php70二.安装切换工具# brew install php-version# source ...