HDU 3911 Black And White(线段树区间合并+lazy操作)
开始以为是水题,结果。。。。。。
给你一些只有两种颜色的石头,0为白色,1为黑色。
然后两个操作:
1 l r 将[ l , r ]内的颜色取反
0 l r 计算[ l , r ]内最长连续黑色石头的个数
明显的线段树区间合并,记录lmax(从左端点开始的最长值) rmax(从右端点开始的最长值) 用于更新mmax(区间最长值)
但是这儿有区间更新,所以记录0的三个最长值和1的三个最长值,更新父节点的时候交换0与1就好。
还有这儿注意查询时,可能值在查询的几个子区间的的相邻处(因为我们只能查询子区间内的最大值,而答案却是几个子区间合在一起的其中某一段)。我们可以根据代码看出,区间查询时一定是从左端点依次不重不漏的进入几个子区间到右端点,所以我们计算最大值时就使用左边的rmax加上右边的lmax。具体看代码
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1E-8
/*注意可能会有输出-0.000*/
#define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
#define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
#define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
typedef long long ll;
typedef unsigned long long ull;
const int Inf=<<;
const double Pi=acos(-1.0);
const int Max=<<;
struct node
{
int llmax,lrmax,lmmax;
int olmax,ormax,ommax;//最长的0个数 用于区间更新
}segtr[Max];
int upn[Max],tem;
int nmax(int a,int b)
{
return a>b?a:b;
}
void Upnow(int now,int next,int sum)//区间更新
{
segtr[now].lmmax=nmax(nmax(segtr[next].lmmax,segtr[next|].lmmax),segtr[next].lrmax+segtr[next|].llmax); segtr[now].llmax=segtr[next].llmax;
if(segtr[next].llmax==sum-(sum>>))
segtr[now].llmax+=segtr[next|].llmax; segtr[now].lrmax=segtr[next|].lrmax;
if(segtr[next|].lrmax==(sum>>))
segtr[now].lrmax+=segtr[next].lrmax; segtr[now].ommax=nmax(nmax(segtr[next].ommax,segtr[next|].ommax),segtr[next].ormax+segtr[next|].olmax); segtr[now].olmax=segtr[next].olmax;
if(segtr[next].olmax==sum-(sum>>))
segtr[now].olmax+=segtr[next|].olmax; segtr[now].ormax=segtr[next|].ormax;
if(segtr[next|].ormax==(sum>>))
segtr[now].ormax+=segtr[next].ormax;
return;
}
void Create(int sta,int enn,int now)
{
upn[now]=;
if(sta==enn)
{
scanf("%d",&tem);
if(tem)//开始tem为1
{
segtr[now].ommax=segtr[now].olmax=segtr[now].ormax=;
segtr[now].lmmax=segtr[now].llmax=segtr[now].lrmax=;
}
else
{
segtr[now].ommax=segtr[now].olmax=segtr[now].ormax=;
segtr[now].lmmax=segtr[now].llmax=segtr[now].lrmax=;
}
return;
}
int mid=dir(sta+enn,);
int next=mul(now,);
Create(sta,mid,next);
Create(mid+,enn,next|);
Upnow(now,next,enn-sta+);
return;
}
void Swap(int &a,int &b)
{
int t=a;
a=b;
b=t;
return;
}
void Cha(int now)//交换此段0与1的个数
{
Swap(segtr[now].lmmax,segtr[now].ommax);
Swap(segtr[now].llmax,segtr[now].olmax);
Swap(segtr[now].lrmax,segtr[now].ormax);
return;
}
void Downow(int now)
{
if(upn[now])
{
int next=mul(now,);
upn[next]=(+upn[next])%;
upn[next|]=(+upn[next|])%;
Cha(next);
Cha(next|);
upn[now]=;
}
return;
}
int ans,mmid;//最终结果 没有断开就继续加
void Update(int sta,int enn,int now,int x,int y,int z)//注意计算结果时虽然有回溯过程,但是一定是从**满足条件的最左边运行到最右边结束**
{
if(sta>=x&&enn<=y)
{
if(z)
{
upn[now]=(upn[now]+)%;
Cha(now);
}
else//**关键是两边区间有连接的情况**
{
mmid+=segtr[now].llmax;
ans=nmax(nmax(ans,mmid),segtr[now].lmmax);
if(segtr[now].llmax==enn-sta+);//整个区间相连
else
mmid=segtr[now].lrmax;
}
return;
}
Downow(now);
int mid=dir(sta+enn,);
int next=mul(now,);
if(mid>=x)
Update(sta,mid,next,x,y,z);
if(mid<y)
Update(mid+,enn,next|,x,y,z);
Upnow(now,next,enn-sta+);
return;
}
int main()
{
int n,m;
int p,lef,rig;
while(~scanf("%d",&n))
{
Create(,n,);
scanf("%d",&m);
while(m--)
{
scanf("%d %d %d",&p,&lef,&rig);
if(!p)
{
mmid=ans=;
Update(,n,,lef,rig,);
printf("%d\n",ans);
}
else
Update(,n,,lef,rig,);
}
}
return ;
}
HDU 3911 Black And White(线段树区间合并+lazy操作)的更多相关文章
- 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之间 ...
- UVA 1400."Ray, Pass me the dishes!" -分治+线段树区间合并(常规操作+维护端点)并输出最优的区间的左右端点-(洛谷 小白逛公园 升级版)
"Ray, Pass me the dishes!" UVA - 1400 题意就是线段树区间子段最大和,线段树区间合并,但是这道题还要求输出最大和的子段的左右端点.要求字典序最小 ...
- hdu 3911 Black And White(线段树)
题目连接:hdu 3911 Black And White 题目大意:给定一个序列,然后有M次操作: 0 l r:表示询问l,r中最大连续1的个数 1 l r:表示将l,r区间上的数取反 解题思路:线 ...
- HDU 3911 Black and White (线段树,区间翻转)
[题目地址] vjudge HDU [题目大意] 海滩上有一堆石头. 石头的颜色是白色或黑色. 小肥羊拥有魔术刷,她可以改变连续石的颜色,从黑变白,从白变黑. 小肥羊非常喜欢黑色,因此她想知道范围 ...
- HDU 1540 Tunnel Warfare(线段树+区间合并)
http://acm.hdu.edu.cn/showproblem.php?pid=1540 题目大意:抗日战争期间进行地道战,存在n个村庄用地道连接,输入D表示破坏某个村庄(摧毁与其相连的地道, 包 ...
- HDU - 1540 Tunnel Warfare(线段树区间合并)
https://cn.vjudge.net/problem/HDU-1540 题意 D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少. 分析 线段树的区间内,我 ...
- HDU 4553 约会安排(线段树区间合并+双重标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 题目大意:就是有三种操作: ①DS x,安排一段长度为x的空闲时间跟屌丝一起,输出这段时间的起点 ...
- hdu 1540 Tunnel Warfare (线段树 区间合并)
Tunnel Warfare Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)To ...
- (简单) HDU 3397 Sequence operation,线段树+区间合并。
Problem Description lxhgww got a sequence contains n characters which are all '0's or '1's. We have ...
随机推荐
- 12. javacript高级程序设计-DOM2和DOM3
1. DOM2和DOM3 DOM2级规范定义了一些模块,用于增强DOM1级.“DOM2级核心”为不同的DOM类型引入了一些与XML命名空间有关的方法,这些变化只在使用XML或者XHTML,对于HTML ...
- poj 1102.LC-Display 解题报告
题目链接:http://poj.org/problem?id=1102 题目意思:就是根据给出的格式 s 和 数字 n,输出数值 n 的 LCD 显示.数值 n 的每个数字要占据 s + 2 列 和 ...
- NIS域配置详解
一.前期准备1.1 NIS 简介NIS,英文的全称是network information service,也叫yellow pages.在Linux中,NIS是一个基于RPC的client/serv ...
- 查看Linux内核
方法一: 命令: uname -a 作用: 查看系统内核版本号及系统名称 方法二: 命令: cat /proc/version 作用: 查看目录"/proc"下version的信息 ...
- Java常用工具类题库
一. 填空题 在Java中每个Java基本类型在java.lang包中都在一个相应的包装类,把基本类型数据转换为对象,其中包装类Integer是___Number__的直接子类. 包装类Inte ...
- oc弹出框显示提示消息
- (void)ShowHUDTitle:(NSString *)title andDelay:(NSTimeInterval)delayTime { if (HUD) { [HUD removeFr ...
- RedHat下安装MySQL
下载mysql 解压tar -xvf mysql-5.7.16-1.el6.x86_64.rpm-bundle.tar 安装MySQL-server包 rpm -ivh mysql-community ...
- IT人学习方法论(一):学习方向
07年的时候曾经讲过一节Webcast,名叫<使您成为Windows专家的一些学习习惯 >.直到最近,还经常收到听众关于这一节课反馈和心得的电子邮件,可见学习方法论是大家非常关心的问题.因 ...
- jQuery – 6.选择器
1. 属性过滤选择器: 1. $("div[id]")选取有id属性的<div> 2. $("div[title=test]")选取title属性为 ...
- Mybatis 字符绑定
http://blog.csdn.net/softwarehe/article/details/8889206