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 ...
随机推荐
- c# 获取系统版本,获取net framework 版本(Environment 类)
1.获取当前操作系统版本信息 使用Environment.OSVersion 属性 获取包含当前平台标识符和版本号的 OperatingSystem 对象. 命名空间: System程序集: ms ...
- selinux
root@lujie ~]# vim /etc/sysconfig/selinux # This file controls the state of SELinux on the system. # ...
- 在HTML网页中设置弹出窗口的办法
[1.最基本的弹出窗口代码] 其实代码非常简单: <SCRIPT LANGUAGE="javascript"> <!-- window.open ('page.h ...
- web前端打印总结
资料: http://blog.5ibc.net/p/39927.html 正文: 简单的说就是映入两个css文件 <link/> <link/> 每个css文件都有一个属性是 ...
- UVa1592_数据库
#include<iostream> #include<cstdio> #include<vector> #include<utility> #incl ...
- html+css+js实现标签页切换
CSS部分: #Tab { margin:0 auto; width:640px; border:none; position:absolute; z-index:9; margin-left:320 ...
- iOS - property,strong,weak,retain,assign,copy,nomatic 的区别及使用
1:ARC环境下,strong代替retain.weak代替assign,xcode 4.2(ios sdk4.3和以下版本)和之前的版本使用的是retain和assign,是不支持ARC的.xcod ...
- markdown思维导图笔记
- AngularJS 简介、指令、表达式
AngularJS 是一个 JavaScript 框架.它可通过 <script> 标签添加到 HTML 页面. AngularJS 通过指令扩展了 HTML,且通过表达式绑定数据到 HT ...
- "".equals(str)和str.equals("")的区别
如果当str为null的话 "".equals(str)不会报空指针异常,而str.equals("")会报异常.这种方式主要用来防止空指针异常