【题目地址】

  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,j]中的石头颜色,并且x = 0表示询问 [i,j]范围内连续黑宝石的最长时间
  • 当x = 0输出时,数字表示范围为[i,j]的黑色宝石的最长长度。

【样例输入】

4

1 0 1 0

5

0 1 4

1 2 3

0 1 4

1 3 3

0 4 4

【样例输出】

1

2

0

【一句话题意】

  • 操作指令为0:

  查询【L, R】中最长的连续的1的个数

  • 操作指令为1:

  将区间【L, R】中的0和1翻转

【难点】

  没办法一步到位求得连续1的个数,如果强买强卖,就是暴力,我们的良心会受到谴责

【突破】逆推,运用分治的思想化繁为简

  1.我们想要维护区间最长连续1的个数,只需要知道每个子区间内最大前缀1,

   最大后缀1(原因先自己思考下)   

  2.想要维护答案和上述两个后缀长度,并且包含修改操作,那么可以去维护对应的0的个数,

   即区间最长连续0的个数,区间最大前缀0,最大后缀0   

  3.众所周知,区间修改需要lazytag(懒标记)   

  4.(此时没明白不打紧,先往后看)

【思路梳理】

  一、需要维护的7个变量:

    区间最大前缀1

    区间最大前缀0

    区间最大后缀1

    区间最大后缀0

    区间最大连续1

    区间最大连续0

    懒惰标记

  二、修改操作

    向下更改时交换所有0,1相关值

  三、查询

    分割区间     

    计算左子区间最大后缀1与当前区间最大前缀1     

    计算右子区间最大前缀1与当前区间最大后缀1     

    将2、3条取max即为所求

  四、注意细节,代码实现

  

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define int long long
using namespace std; inline int read(){
int x = , w = ;
char ch = getchar();
for(; ch > '' || ch < ''; ch = getchar()) if(ch == '-') w = -;
for(; ch >= '' && ch <= ''; ch = getchar()) x = x * + ch - '';
return x * w;
} const int maxn = ;
int a[maxn]; struct node{
int l0, r0;
int l1, r1;
int max0, max1;
int lazytag;
}tree[maxn << ]; inline void solve(int u, int l, int r){//维护7个相关值
int mid = (l + r) >> ;
//前缀1
tree[u].l1 = tree[u << ].l1;
if(tree[u].l1 == mid - l + ){
tree[u].l1 += tree[u << | ].l1;
}
//前缀0
tree[u].l0 = tree[u << ].l0;
if(tree[u].l0 == mid - l + ){
tree[u].l0 += tree[u << | ].l0;
}
//后缀1
tree[u].r1 = tree[u << | ].r1;
if(tree[u].r1 == r - mid){
tree[u].r1 += tree[u << ].r1;
}
//后缀0
tree[u].r0 = tree[u << | ].r0;
if(tree[u].r0 == r - mid){
tree[u].r0 += tree[u << ].r0;
}
//区间最大1,最大0
tree[u].max1 = max (max (tree[u << ].max1, tree[u << | ].max1), tree[u << ].r1 + tree[u << | ].l1);
tree[u].max0 = max (max (tree[u << ].max0, tree[u << | ].max0), tree[u << ].r0 + tree[u << | ].l0);
} inline void SWAP(int u){//保留备用,每次做区间翻转的时候要用
swap(tree[u].l0, tree[u].l1);
swap(tree[u].r0, tree[u].r1);
swap(tree[u].max0, tree[u].max1);
} inline void pushdown(int u, int l, int r){//懒标记下防
if(l != r){
tree[u << ].lazytag ^= ;
tree[u << | ].lazytag ^= ;
SWAP(u << );
SWAP(u << | );
tree[u].lazytag = ;
}
} int tmp;
inline void build(int u, int l, int r){//建树
tree[u].lazytag = ;
if(l == r){
tmp = read();
if(tmp == ){//若当前石头为黑色
tree[u].l1 = tree[u].r1 = tree[u].max1 = ;
tree[u].l0 = tree[u].r0 = tree[u].max0 = ;
}
else{//为白色
tree[u].l1 = tree[u].r1 = tree[u].max1 = ;
tree[u].l0 = tree[u].r0 = tree[u].max0 = ;
}
return;
}
int mid = (l + r) >> ;
build(u << , l, mid);//左子树
build(u << | , mid + , r);//右子树
solve(u, l, r);//维护7个相关值
} inline void change(int u, int l, int r, int s, int t){//区间翻转
if(l >= s && r <= t){//更新lazytag
tree[u].lazytag ^= ;
SWAP(u);
return;
}
if(tree[u].lazytag) pushdown(u, l, r);
int mid = (l + r) >> ;
if(mid >= t)
update(u << , l, mid, s, t);
else if(mid < s)
update(u << | , mid + , r, s, t);
else{
update(u << , l, mid, s, t);
update(u << | , mid + , r, s, t);
}
solve(u, l, r);//维护7个相关值
} inline int query(int u, int l, int r, int s, int t){
if(l >= s && r <= t){
return tree[u].max1;
}
if(tree[u].lazytag) pushdown(u, l ,r);
int mid = (l + r) >> ;
if(mid >= t) return query(u << , l, mid, s, t);
else if(mid < s) return query(u << | , mid + , r, s, t);
else{
int cnt1 = query(u << , l, mid, s, t);
int cnt2 = query(u << | , mid + , r, s, t);
int cnt3 = min(mid - s + , tree[u << ].r1);
int cnt4 = min(t - mid, tree[u << | ].l1);
return max(max(cnt1, cnt2), cnt3 + cnt4);
}
solve(u, l, r);
} signed main(){
int n;
while(scanf("%lld", &n) == ){
build(, , n);
int m = read();
while(m--){
int opt = read(), l = read(), r = read();
if(opt == )//翻转
change(, , n, l, r);
else//查询
printf("%lld\n", query(, , n, l, r));
}
}
return ;
}

HDU 3911

  

HDU 3911 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(线段树)

    题目连接:hdu 3911 Black And White 题目大意:给定一个序列,然后有M次操作: 0 l r:表示询问l,r中最大连续1的个数 1 l r:表示将l,r区间上的数取反 解题思路:线 ...

  3. HDU.1556 Color the ball (线段树 区间更新 单点查询)

    HDU.1556 Color the ball (线段树 区间更新 单点查询) 题意分析 注意一下pushdown 和 pushup 模板类的题还真不能自己套啊,手写一遍才行 代码总览 #includ ...

  4. HDU.1689 Just a Hook (线段树 区间替换 区间总和)

    HDU.1689 Just a Hook (线段树 区间替换 区间总和) 题意分析 一开始叶子节点均为1,操作为将[L,R]区间全部替换成C,求总区间[1,N]和 线段树维护区间和 . 建树的时候初始 ...

  5. HDU 1698 Just a Hook(线段树 区间替换)

    Just a Hook [题目链接]Just a Hook [题目类型]线段树 区间替换 &题解: 线段树 区间替换 和区间求和 模板题 只不过不需要查询 题里只问了全部区间的和,所以seg[ ...

  6. HDU 1556 Color the ball(线段树区间更新)

    Color the ball 我真的该认真的复习一下以前没懂的知识了,今天看了一下线段树,以前只会用模板,现在看懂了之后,发现还有这么多巧妙的地方,好厉害啊 所以就应该尽量搞懂 弄明白每个知识点 [题 ...

  7. (简单) HDU 1698 Just a Hook , 线段树+区间更新。

    Description: In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of ...

  8. HDU 1698 Just a Hook(线段树区间更新查询)

    描述 In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes ...

  9. hdu 1556 Color the ball(线段树区间维护+单点求值)

    传送门:Color the ball Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/3276 ...

随机推荐

  1. Windows下虚拟机Linux(CentOS8)扩容设置 - 磁盘扩容中的坑和解决方法

    摘要:[原创]转载请注明作者Johnthegreat和本文链接 由于虚拟机空间不足,为了避免重装虚拟机,做了一次无损扩容.   过程中的报错如下: [root@localhost ~]# pvcrea ...

  2. 温故知新-java虚拟机

    文章目录 java虚拟机是什么? jvm的体系结构 第一个类加载子系统 类的生命周期 加载器分类 类加载机制 第二个运行时数据区(内存结构) GC算法和收集器 如何判断对象可以被回收? 如何判断一个常 ...

  3. Python数据分析软件包介绍

    Python数据分析主要软件包: 1.python -m pip install numpy 2.python -m pip install pandas 3.python -m pip instal ...

  4. SuperSlide之属性targetCell介绍

    禁用页面菜单js代码: <script type="text/javascript"> document.oncontextmenu=function(){ retur ...

  5. css3动画特效代码

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. IDEA之maven配置详解

    这两天被maven配置搞得焦头烂额,前后忙活了三天才彻底搞定. 下面我总结一下配置的步骤. 步骤 1. 首先去maven官网去下载maven,http://maven.apache.org/ 这里教大 ...

  7. winXP vc6行号显示插件-VC6LineNumberAddin方法-可用-无需注册

    1.VC6LineNumberAddin 修改日期是2008.6.3可用,其它需要注册码 http://codefish.googlecode.com/files/VC%E6%98%BE%E7%A4% ...

  8. PHP丨PHP基础知识之PHP基础入门——函数「理论篇」

    前两天讲过PHP基础知识的判断条件和流程控制,今天来讲讲PHP基础知识之PHP基础入门--函数! 一.函数的声明与使用 1.函数名是标识符之一,只能有数字字母下划线,开头不能是数字. 函数名的命名,须 ...

  9. 一个老牌程序员说:做Java开发,怎么可以不会这 20 种类库和 API

  10. Domain Adaptive Faster R-CNN:经典域自适应目标检测算法,解决现实中痛点,代码开源 | CVPR2018

    论文从理论的角度出发,对目标检测的域自适应问题进行了深入的研究,基于H-divergence的对抗训练提出了DA Faster R-CNN,从图片级和实例级两种角度进行域对齐,并且加入一致性正则化来学 ...