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);//整个区间相连 else mmid=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); } else Update(1,n,1,lef,rig,1); } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决