【题目地址】

  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. keras搭建神经网络快速入门笔记

    之前学习了tensorflow2.0的小伙伴可能会遇到一些问题,就是在读论文中的代码和一些实战项目往往使用keras+tensorflow1.0搭建, 所以本次和大家一起分享keras如何搭建神经网络 ...

  2. 浅谈Unity的脚本执行顺序

    一.添加脚本的顺序 这是一张官方的脚本顺序图 一般,当我们把脚本绑定在游戏对象上时,或者点击绑定好的脚本的reset按钮时,会调用Reset() 当我们初始化一个对象时,会先调用Awake()在调用O ...

  3. PAT 1041 Be Unique (20分)利用数组找出只出现一次的数字

    题目 Being unique is so important to people on Mars that even their lottery is designed in a unique wa ...

  4. Mybatis详解(二) sqlsession的创建过程

    我们处于的位置 我们要清楚现在的情况. 现在我们已经调用了SqlSessionFactoryBuilder的build方法生成了SqlSessionFactory 对象. 但是如标题所说,要想生成sq ...

  5. Java StringTokenizer 类使用方法,字符串分割

    Java StringTokenizer 属于 java.util 包,用于分隔字符串. StringTokenizer 构造方法: StringTokenizer(String str) :构造一个 ...

  6. centos7.2挂载硬盘攻略

    远程SSH登录上CentOS服务器后,进行如下操作: 提醒:挂载操作会清空数据,请确认挂载盘无数据或者未使用 第一步:列出所有磁盘 命令: ll /dev/disk/by-path ll /dev/d ...

  7. 「JOISC 2020 Day4」首都城市

    题目   点这里看题目. 分析   做法比较容易看出来.我们对于每个城市,找出那些 " 如果这个城市在首都内,则必须在首都内的其它城市 " ,也就是为了让这个城市的小镇连通而必须选 ...

  8. excel 如何制作带下拉框的动态折线图表

    首先我们需要有个类似下图产品销量的基础数据表. 首先将光标放入表格中任意位置,然后插入一个不带点标记的折线图,然后将折线的颜色设置为灰色. 第一次设置成灰色后,一定善用f4快捷键进行快速的折线颜色设置 ...

  9. Arduino+sim800C家居安防火灾报警 拨打电话 发送短信例程程序

    家居安防报警器,参考程序. 火灾报警 涉及用sim800c发短信,拨打电话通知. 接线: Sim800c 3.3V -> Arduino 3.3V Sim800c GND -> Ardui ...

  10. C#数据结构与算法系列(八):栈(Stack)

    1.介绍 栈是一个先入后出(FILO-First In Last Out)的有序列表 栈是限制线性表中元素的插入和删除只能在线性表的同一端进行的特殊线性表.允许插入和删除的一端,为变化的一端,称为栈顶 ...