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=1<<28; const double Pi=acos(-1.0); const int Max=100010<<2; 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|1].lmmax),segtr[next].lrmax+segtr[next|1].llmax);segtr[now].llmax=segtr[next].llmax;if(segtr[next].llmax==sum-(sum>>1))segtr[now].llmax+=segtr[next|1].llmax;segtr[now].lrmax=segtr[next|1].lrmax;if(segtr[next|1].lrmax==(sum>>1))segtr[now].lrmax+=segtr[next].lrmax;segtr[now].ommax=nmax(nmax(segtr[next].ommax,segtr[next|1].ommax),segtr[next].ormax+segtr[next|1].olmax);segtr[now].olmax=segtr[next].olmax;if(segtr[next].olmax==sum-(sum>>1))segtr[now].olmax+=segtr[next|1].olmax;segtr[now].ormax=segtr[next|1].ormax;if(segtr[next|1].ormax==(sum>>1))segtr[now].ormax+=segtr[next].ormax;return; } void Create(int sta,int enn,int now) {upn[now]=0;if(sta==enn){scanf("%d",&tem);if(tem)//开始tem为1 {segtr[now].ommax=segtr[now].olmax=segtr[now].ormax=0;segtr[now].lmmax=segtr[now].llmax=segtr[now].lrmax=1;}else{segtr[now].ommax=segtr[now].olmax=segtr[now].ormax=1;segtr[now].lmmax=segtr[now].llmax=segtr[now].lrmax=0;}return;}int mid=dir(sta+enn,1);int next=mul(now,1);Create(sta,mid,next);Create(mid+1,enn,next|1);Upnow(now,next,enn-sta+1);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,1);upn[next]=(1+upn[next])%2;upn[next|1]=(1+upn[next|1])%2;Cha(next);Cha(next|1);upn[now]=0;}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]+1)%2;Cha(now);}else//**关键是两边区间有连接的情况** {mmid+=segtr[now].llmax;ans=nmax(nmax(ans,mmid),segtr[now].lmmax);if(segtr[now].llmax==enn-sta+1);//整个区间相连elsemmid=segtr[now].lrmax;}return;}Downow(now);int mid=dir(sta+enn,1);int next=mul(now,1);if(mid>=x)Update(sta,mid,next,x,y,z);if(mid<y)Update(mid+1,enn,next|1,x,y,z);Upnow(now,next,enn-sta+1);return; } int main() {int n,m;int p,lef,rig;while(~scanf("%d",&n)){Create(1,n,1);scanf("%d",&m);while(m--){scanf("%d %d %d",&p,&lef,&rig);if(!p){mmid=ans=0;Update(1,n,1,lef,rig,0);printf("%d\n",ans);}elseUpdate(1,n,1,lef,rig,1);}}return 0; }
转载于:https://www.cnblogs.com/zhuanzhuruyi/p/5863691.html
HDU 3911 Black And White(线段树区间合并+lazy操作)相关推荐
- HDU 3397 Sequence operation(线段树区间合并)
题意: 0 a b将区间[a,b]所有数全部变成0 1 a b将区间[a,b]所有数全部变成1 2 a b将区间[a,b]中所有数0 1互换,0变1,1变0 3 a b输出区间[a,b]中1的个数 4 ...
- HDU - 6406 Taotao Picks Apples(线段树区间合并)
题目链接:点击查看 题目大意:给出一个长度为 n 的数列 a,再给出 m 次询问,每次询问假设如果设置 a[ pos ] = val 的话,那么此时序列中的最长上升子序列是多少,此时的上升子序列指的是 ...
- hdu3911 Black And White (线段树/区间合并)
题目 n(n<=1e5)个数的数列,每个数只可能是0或1 m(m<=1e5)个操作,操作分两种 1 x y 代表 将[x,y]内所有数都取反 0 x y 询问 [x,y]内最长连续1的个数 ...
- Tunnel Warfare(HDU1540+线段树+区间合并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540 题目: 题意:总共有n个村庄,有q次操作,每次操作分为摧毁一座村庄,修复一座村庄,和查询与询问的 ...
- HDU3308 线段树区间合并
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 ,简单的线段树区间合并. 线段树的区间合并:一般是要求求最长连续区间,在PushUp()函数中实 ...
- 树链剖分——线段树区间合并bzoj染色
线段树区间合并就挺麻烦了,再套个树链就更加鬼畜,不过除了代码量大就没什么其他的了.. 一些细节:线段树每个结点用结构体保存,pushup等合并函数改成返回一个结构体,这样好写一些 struct Seg ...
- SPOJ GSS3-Can you answer these queries III-分治+线段树区间合并
Can you answer these queries III SPOJ - GSS3 这道题和洛谷的小白逛公园一样的题目. 传送门: 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间 ...
- CodeForces - 1539F Strange Array(线段树区间合并)
题目链接:点击查看 题目大意:给出一个长度为 nnn 的序列,规定位置 iii 的贡献是:设 x=a[i]x=a[i]x=a[i],选择一个包含 iii 的区间 [l,r][l,r][l,r],将其中 ...
- 牛客 - 求函数(线段树+区间合并/线段树+矩阵维护)
题目链接:点击查看 题目大意:现在有 n 个函数,每个函数都是诸如 f( x ) = k * x + b 的形式,只是每个函数的 k 和 b 都是相互独立的,现在给出两个操作: 1 pos k b:将 ...
- 2021牛客暑期多校训练营7 xay loves monotonicity 线段树区间合并
传送门 文章目录 题意: 思路: 题意: 题面挺绕口的,还是看原题比较好. 大概的意思就是让你从给定的区间中选择一个以左端点为起点的一个上升子序列,让后将这些下标存下来,在bbb中将这些位置拿出来后, ...
最新文章
- Spring4中的@Value的使用(学习笔记)
- css默认样式以及解决办法
- Qt文档阅读笔记-Broadcast Receiver Example解析
- linux关闭cups命令,使用linux的cupsenable命令启动指定的打印机
- theme为dialog的Activity如何充满全屏
- 【交易技术前沿】低时延基础设施杂谈
- 分享如何设计调查问卷怎样分析问卷数据!
- 为什么要使用版本管理
- iview表格序号1,2,3,4,5
- 麻省理工的服务器位置,美国麻省理工学院的地理位置
- 大数据专业找工作分析
- Jenkins RestAPI调用出现Error 403 No valid crumb was included in the request [亲测有用]
- 表格内容相同单元格合并
- 第四周 放大电路的分析
- Python Flask框架-开发简单博客-认证蓝图
- 经济学里的那些字母都代表的意思
- ctf镜子里面的世界_通过机械装置,这名艺术家把木头和玩偶做成了“镜子”
- 【MySQL】聚合函数
- seo关键字优化条例
- shell文件编辑器之sed