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 ...
随机推荐
- Linux内存管理原理
本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址又叫线性地址.linux没有采用分段机制,所以逻辑地址和虚拟地址(线性地址)(在用户态,内核态逻 ...
- zsh 通信脚本
server #!/bin/zsh #zsh TCP server script zmodload zsh/net/tcp #listening port ztcp -l #This is a fil ...
- Mathematics:GCD & LCM Inverse(POJ 2429)
根据最大公约数和最小公倍数求原来的两个数 题目大意,不翻译了,就是上面链接的意思. 具体思路就是要根据数论来,设a和b的GCD(最大公约数)和LCM(最小公倍数),则a/GCD*b/GCD=LCM/G ...
- codeforces 507B. Painting Pebbles 解题报告
题目链接:http://codeforces.com/problemset/problem/509/B 题目意思:有 n 个piles,第 i 个 piles有 ai 个pebbles,用 k 种颜色 ...
- hdu 1002.A + B Problem II 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1002 题目意思:就是大整数加法. 两年几前做的,纯粹是整理下来的. #include <stdi ...
- spfa(模板)
spfa作为图论中的常用算法,深受各类出题人和各位OIer的喜爱: so,为了给大众创造福利,宝宝在此奉上spfa大发的思路和模板:以感谢社会, 感谢CCF,感谢CCTV, 感谢我的老师,感谢同学们, ...
- ios NSLayoutConstraint
为了让我们的应用在不同尺寸的屏幕下都能 “正常”的表示,我们尽量不要把数据写死.大多数可视元素都是一个矩形区域,当然这个矩形区域有坐标的,我们有了这个区域坐标就能确定可视元素的现实位置了.但是ipho ...
- PHP工厂模式的研究
工厂方法模式 把 创造者类 和要生产的 产品类 分离.创建者是一个工厂类,其定义了产品生产的类方法.一般情况下,创建者类的每个子类实例化一个相应的产品子类. 下面是单个产品的实现代码: <?ph ...
- 240个jquery插件(转)
http://www.kollermedia.at/archive/2007/11/21/the-ultimate-jquery-plugin-list/File upload Ajax File U ...
- 读取Spring的配置文件applicationContext.xml的5种方法
1.利用ClassPathXmlApplicationContext,这种方式配置文件应该放在类包同路径下Java代码: ApplicationContext ct=new ClassPathXmlA ...