欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ1858
题意概括
lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:0 a b把[a,b]区间内的所有数全变成 0,1 a b把[a,b]区间内的所有数全变成1,2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0,3 a b询问[a,b]区间内总共 有多少个1,4 a b询问[a,b]区间内最多有多少个连续的1,对于每一种询问操作,lxhgww都需要给出回答
题解
是一题暴力的线段树!
总共除了1的总个数之外,还要维护6个量,分别是(当前区间内)从左开始连续的0的个数,从又开始连续的0的个数,区间内最长的连续的0的个数;同理,1也有3个。这题多打几个子程序是缩减代码量的好方法,这样便于查找错误。这题真的拼仔细!
代码
#include <cstring>
#include <cstdio>
int n,m,ra[101000],op,a,b;
int max2(int a,int b){return a>b?a:b;}
int max3(int a,int b,int c){return max2(max2(a,b),c);}
struct Segtree{
int tot,add,t100,t101,t110,t000,t001,t010,le,ri,si;
void set(int l,int r){
tot=t100=t101=t110=t000=t001=t010=0;
add=-1,le=l,ri=r,si=ri-le+1;
}
}t[101000*4];
void swap(int &a,int &b){
int c=a;a=b,b=c;
}
void pushup(int rt){
int ls=rt*2,rs=rt*2+1;
t[rt].tot=t[ls].tot+t[rs].tot;
t[rt].t110=t[ls].t110;
if (t[ls].t110==t[ls].si)
t[rt].t110+=t[rs].t110;
t[rt].t101=t[rs].t101;
if (t[rs].t101==t[rs].si)
t[rt].t101+=t[ls].t101;
t[rt].t100=max3(t[ls].t101+t[rs].t110,t[ls].t100,t[rs].t100);
t[rt].t010=t[ls].t010;
if (t[ls].t010==t[ls].si)
t[rt].t010+=t[rs].t010;
t[rt].t001=t[rs].t001;
if (t[rs].t001==t[rs].si)
t[rt].t001+=t[ls].t001;
t[rt].t000=max3(t[ls].t001+t[rs].t010,t[ls].t000,t[rs].t000);
}
void build(int rt,int le,int ri){
t[rt].add=-1,t[rt].le=le,t[rt].ri=ri,t[rt].si=ri-le+1;
if (le==ri){
t[rt].tot=t[rt].t101=t[rt].t110=ra[le];
t[rt].t001=t[rt].t010=!ra[le];
return;
}
int mid=(le+ri)/2,ls=rt*2,rs=rt*2+1;
build(ls,le,mid);
build(rs,mid+1,ri);
pushup(rt);
}
void pushnew(int rt,int op){
if (op<2)
t[rt].add=op;
else if (t[rt].add==-1)
t[rt].add=2;
else if (t[rt].add==2)
t[rt].add=-1;
else
t[rt].add=!t[rt].add;
if (op==0)
t[rt].tot=t[rt].t100=t[rt].t101=t[rt].t110=0,t[rt].t000=t[rt].t010=t[rt].t001=t[rt].si;
else if (op==1)
t[rt].tot=t[rt].t100=t[rt].t101=t[rt].t110=t[rt].si,t[rt].t000=t[rt].t010=t[rt].t001=0;
else if (op==2){
t[rt].tot=t[rt].si-t[rt].tot;
swap(t[rt].t000,t[rt].t100);
swap(t[rt].t010,t[rt].t110);
swap(t[rt].t001,t[rt].t101);
}
}
void pushdown(int rt){
if (t[rt].add!=-1){
pushnew(rt*2,t[rt].add);
pushnew(rt*2+1,t[rt].add);
t[rt].add=-1;
}
}
void update(int rt,int le,int ri,int xle,int xri,int op){
if (le>xri||ri<xle)
return;
if (xle<=le&&ri<=xri){
pushnew(rt,op);
return;
}
pushdown(rt);
int mid=(le+ri)/2;
update(rt*2,le,mid,xle,xri,op);
update(rt*2+1,mid+1,ri,xle,xri,op);
pushup(rt);
}
int querytot(int rt,int le,int ri,int xle,int xri){
if (le>xri||ri<xle)
return 0;
if (xle<=le&&ri<=xri)
return t[rt].tot;
pushdown(rt);
int mid=(le+ri)/2;
return querytot(rt*2,le,mid,xle,xri)+querytot(rt*2+1,mid+1,ri,xle,xri);
}
Segtree query(int rt,int le,int ri,int xle,int xri){
Segtree ans;
ans.set(le,ri);
if (le>xri||ri<xle)
return ans;
if (xle<=le&&ri<=xri)
return t[rt];
pushdown(rt);
int mid=(le+ri)/2;
Segtree ls=query(rt*2,le,mid,xle,xri),rs=query(rt*2+1,mid+1,ri,xle,xri);
ans.t110=ls.t110;
if (ls.t110==ls.si)
ans.t110+=rs.t110;
ans.t101=rs.t101;
if (rs.t101==rs.si)
ans.t101+=ls.t101;
ans.t100=max3(ls.t101+rs.t110,ls.t100,rs.t100);
ans.t010=ls.t010;
if (ls.t010==ls.si)
ans.t010+=rs.t010;
ans.t001=rs.t001;
if (rs.t001==rs.si)
ans.t001+=ls.t001;
ans.t000=max3(ls.t001+rs.t010,ls.t000,rs.t000);
return ans;
}
int queryans(int a,int b){
Segtree tt=query(1,1,n,a,b);
return max3(tt.t100,tt.t101,tt.t110);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&ra[i]);
build(1,1,n);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&op,&a,&b);
a++,b++;
if (op<3)
update(1,1,n,a,b,op);
else if (op==3)
printf("%d\n",querytot(1,1,n,a,b));
else if (op==4){
printf("%d\n",queryans(a,b));
}
}
return 0;
}