[BZOJ1858/Luogu2572][SCOI2010]序列操作
题目链接:
为什么我的代码这么长啊。。
这一看就是个线段树裸题,难点在于第\(4\)个操作。
我们需要在线段树上维护\(6\)个值:
Lm0/1
:紧靠左的最长一段\(0/1\)的长度
Rm0/1
:紧靠右的最长一段\(0/1\)的长度
Tm0/1
:整段中的最长一段\(0/1\)的长度
最后注意修改和翻转操作的优先级:修改的优先级最高(显然)。
然后Debug就好了。
代码:
#include <cstdio>
#include <algorithm>
struct Segment_Tree
{
struct Node{int Cnt,Tag,Rev,Lm0,Lm1,Rm0,Rm1,Tm0,Tm1;}a[400005];
//Cnt 1的个数
//Tag -1/0/1:无修改/覆盖为0/覆盖为1
//Rev 0/1 是否翻转
//Lm0/Lm1/Rm0/Rm1/Tm0/Tm1 如上所述
inline void Pushdown(Node &p,Node &ls,Node &rs,const int ll,const int rl)
//将p向ls和rs传播标记
{
if(~p.Tag)
//优先考虑修改
{
ls.Lm0=ls.Rm0=ls.Tm0=(p.Tag^1)*ll,ls.Lm1=ls.Rm1=ls.Tm1=p.Tag*ll;
rs.Lm0=rs.Rm0=rs.Tm0=(p.Tag^1)*rl,rs.Lm1=rs.Rm1=rs.Tm1=p.Tag*rl;
ls.Cnt=p.Tag*ll,rs.Cnt=p.Tag*rl,ls.Tag=rs.Tag=p.Tag,p.Tag=-1,p.Rev=0;
//修改后不考虑翻转,清空标记
}
if(p.Rev)
{
if(~ls.Tag)ls.Tag^=1;if(~rs.Tag)rs.Tag^=1;
ls.Rev^=1,rs.Rev^=1,ls.Cnt=ll-ls.Cnt,rs.Cnt=rl-rs.Cnt,p.Rev=0;
std::swap(ls.Lm0,ls.Lm1),std::swap(rs.Lm0,rs.Lm1);
std::swap(ls.Rm0,ls.Rm1),std::swap(rs.Rm0,rs.Rm1);
std::swap(ls.Tm0,ls.Tm1),std::swap(rs.Tm0,rs.Tm1);
//翻转操作,也就是0/1的信息互换
}
}
inline Node Pushup(const Node &a,const Node &b,const int al,const int bl)
//合并a和b,al为a的长度,bl同理
{
Node Res;
Res.Cnt=a.Cnt+b.Cnt,Res.Tag=-1,Res.Rev=0;
Res.Lm0=!a.Cnt?al+b.Lm0:a.Lm0;
Res.Lm1=a.Cnt==al?al+b.Lm1:a.Lm1;
Res.Rm0=!b.Cnt?bl+a.Rm0:b.Rm0;
Res.Rm1=b.Cnt==bl?bl+a.Rm1:b.Rm1;
Res.Tm0=std::max(std::max(a.Tm0,b.Tm0),a.Rm0+b.Lm0);
Res.Tm1=std::max(std::max(a.Tm1,b.Tm1),a.Rm1+b.Lm1);
return Res;
}
void Build(const int p,const int l,const int r)
{
if(a[p].Tag=-1,l==r)
{
scanf("%d",&a[p].Cnt);
if(a[p].Cnt)a[p].Lm1=a[p].Rm1=a[p].Tm1=1;
else a[p].Lm0=a[p].Rm0=a[p].Tm0=1;
return;
}
const int Mid=(l+r)>>1;
Build(p<<1,l,Mid),Build(p<<1|1,Mid+1,r);
a[p]=Pushup(a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
}
void Cover(const int p,const int l,const int r,const int tl,const int tr,const int v)
//覆盖操作
{
if(tl<=l&&r<=tr)
{
a[p].Cnt=v*(r-l+1),a[p].Tag=v;
a[p].Lm0=a[p].Rm0=a[p].Tm0=(v^1)*(r-l+1);
a[p].Lm1=a[p].Rm1=a[p].Tm1=v*(r-l+1);
return;
}
const int Mid=(l+r)>>1;
Pushdown(a[p],a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
if(tl<=Mid)Cover(p<<1,l,Mid,tl,tr,v);
if(tr>Mid)Cover(p<<1|1,Mid+1,r,tl,tr,v);
a[p]=Pushup(a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
}
void Reverse(const int p,const int l,const int r,const int tl,const int tr)
//翻转操作
{
if(tl<=l&&r<=tr)
{
if(~a[p].Tag)a[p].Tag^=1;
//注意优先级
a[p].Cnt=r-l+1-a[p].Cnt,a[p].Rev^=1;
std::swap(a[p].Lm0,a[p].Lm1);
std::swap(a[p].Rm0,a[p].Rm1);
std::swap(a[p].Tm0,a[p].Tm1);
return;
}
const int Mid=(l+r)>>1;
Pushdown(a[p],a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
if(tl<=Mid)Reverse(p<<1,l,Mid,tl,tr);
if(tr>Mid)Reverse(p<<1|1,Mid+1,r,tl,tr);
a[p]=Pushup(a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
}
int Query_Cnt(const int p,const int l,const int r,const int tl,const int tr)
//查询1的个数
{
if(tl<=l&&r<=tr)return a[p].Cnt;
int Mid=(l+r)>>1,Res=0;
Pushdown(a[p],a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
if(tl<=Mid)Res=Query_Cnt(p<<1,l,Mid,tl,tr);
if(tr>Mid)Res+=Query_Cnt(p<<1|1,Mid+1,r,tl,tr);
return Res;
}
Node Query_Con(const int p,const int l,const int r,const int tl,const int tr)
//查询连续1的长度
{
if(tl<=l&&r<=tr)return a[p];
const int Mid=(l+r)>>1;
Pushdown(a[p],a[p<<1],a[p<<1|1],Mid-l+1,r-Mid);
if(tr<=Mid)return Query_Con(p<<1,l,Mid,tl,tr);
if(tl>Mid)return Query_Con(p<<1|1,Mid+1,r,tl,tr);
return Pushup(Query_Con(p<<1,l,Mid,tl,tr),Query_Con(p<<1|1,Mid+1,r,tl,tr),Mid-l+1,r-Mid);
}
}Sequence;
int main()
{
int n,m;scanf("%d%d",&n,&m),Sequence.Build(1,1,n);
for(int op,l,r;m--;)
if(scanf("%d%d%d",&op,&l,&r),++l,++r,op<=1)Sequence.Cover(1,1,n,l,r,op);
else if(op==2)Sequence.Reverse(1,1,n,l,r);
else if(op==3)printf("%d\n",Sequence.Query_Cnt(1,1,n,l,r));
else printf("%d\n",Sequence.Query_Con(1,1,n,l,r).Tm1);
return 0;
}