毒瘤线段树,调了一下午+一晚上%%%hzwer大爷
我们需要维护
zero[0]:从当前区间左端点开始有多少个连续的0 one[0]:从当前区间左端点开始有多少个连续的1
zero[1]:从当前区间右端点开始有多少个连续的0 one[1]:从当前区间右端点开始有多少个连续的1
zero[2]:当前区间最长的连续的0的个数 one[2]:当前区间最长的连续的1的个数
sum[0]:当前区间0的个数 sum[1]:当前区间1的个数
lazy=-1:当前区间没有全部为1或0的操作
lazy=0:当前区间要全部换成0
lazy=1:当前区间要全部换成1
f=0/1 :区间不需要/需要进行翻转操作
full=-1/0/1:当前区间既有0也有1/只有0/只有1
然后我们考虑如何更新,大区间的左端点的值用左儿子更新,右端点的值用右儿子更新,区间最值在两个儿子中取max
然后考虑几个特殊情况,ls.full=0,也就是说左儿子全是0,那么大区间的zero[0]就可以加上右儿子的zero[0]因为这两段连起来了
同理ls.full=1的情况也要加上右儿子的one[1],右儿子同理
区间最值
zero[0]=max{ls.zero[0],rs.zero[0],ls.zero[1]+rs.zero[0]}就是说在两个子区间的最大值与中间连续一段的长度中取max
lazy操作
lazy的优先级要大于翻转的优先级,一旦有了lazy,那么翻转就要清空
全置成0的话zero[0]=zero[1]=zero[2]=sum[0]=len(区间长),1也同理,但我们要同时更新,那就:
zero[0]=zero[1]=zero[2]=sum[0]=len*(lazy^1) one[0]=one[1]=one[2]=sum[1]=len*lazy (自己感性理解为什么
记得清空翻转操作和更新full标记
f 翻转操作
翻转就是0和1互换嘛,相应的zero 和 one也互换一下就好了,还有 full标记
查询区间和就是1的个数,最长连续1就递归在左右区间取max一直更新就吼啦!
代码
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ls x<<1
#define rs x<<1|1
#define lb t[x].b[0]
#define rb t[x].b[1]
using namespace std;
const int M=500500;
struct Seg
{
int b[2],z[3];
int la,f,o[3];
int s[2],full;
Seg(){b[0]=b[1]=z[0]=z[1]=z[2]=o[0]=o[1]=o[2]=s[0]=s[1]=f=0;la=full=-1;}
}t[M];
int n,m;
inline Seg up(Seg x,Seg y)
{
Seg e;e.f=0;e.la=-1;
e.b[0]=x.b[0]; e.b[1]=y.b[1];
e.z[0]=x.z[0]; e.z[1]=y.z[1];
e.o[0]=x.o[0]; e.o[1]=y.o[1];
e.z[2]=max(x.z[2],y.z[2]);
e.o[2]=max(x.o[2],y.o[2]);
e.z[2]=max(e.z[2],x.z[1]+y.z[0]);
e.o[2]=max(e.o[2],x.o[1]+y.o[0]);
e.s[0]=x.s[0]+y.s[0];e.s[1]=x.s[1]+y.s[1];
if(x.full==0) e.z[0]=x.z[2]+y.z[0];
if(x.full==1) e.o[0]=x.o[2]+y.o[0];
if(y.full==0) e.z[1]=y.z[2]+x.z[1];
if(y.full==1) e.o[1]=y.o[2]+x.o[1];
e.full=(x.full==y.full)?x.full:-1;
return e;
}
inline void cover(int x,int v)
{
t[x].f=0;t[x].la=v;int len=rb-lb+1;t[x].full=v;
t[x].s[1]=t[x].o[0]=t[x].o[1]=t[x].o[2]=v*len;
t[x].s[0]=t[x].z[0]=t[x].z[1]=t[x].z[2]=(v^1)*len;
return ;
}
inline void rever(int x)
{
swap(t[x].z[0],t[x].o[0]);swap(t[x].o[1],t[x].z[1]);
swap(t[x].z[2],t[x].o[2]);swap(t[x].s[0],t[x].s[1]);
t[x].f^=1;if (t[x].full!=-1) t[x].full^=1;
return ;
}
inline void down(int x)
{
if (lb==rb) return ;
if (t[x].la!=-1)
cover(ls,t[x].la),cover(rs,t[x].la),t[x].la=-1;
if (t[x].f)
rever(ls),rever(rs),t[x].f=0;
return ;
}
inline void built(int l,int r,int x)
{
t[x].b[0]=l;t[x].b[1]=r;t[x].la=-1;
if (l==r)
{
scanf("%d",&t[x].full);
t[x].o[0]=t[x].o[1]=t[x].o[2]=t[x].s[1]=t[x].full;
t[x].z[0]=t[x].z[1]=t[x].z[2]=t[x].s[0]=t[x].full^1;
return ;
}
int mid=(l+r)>>1;
built(l,mid,ls);built(mid+1,r,rs);
return (void)(t[x]=up(t[ls],t[rs]));
}
inline void update(int l,int r,int x,int v)
{
down(x);
if (l<=lb&&rb<=r) return (void)(cover(x,v));
int mid=(lb+rb)>>1;
if (l<=mid) update(l,r,ls,v);
if (r>mid) update(l,r,rs,v);
return (void)(t[x]=up(t[ls],t[rs]));
}
inline void upturn(int l,int r,int x)
{
down(x);
if (l<=lb&&rb<=r)
{
rever(x),t[x].f=1;
return ;
}
int mid=(lb+rb)>>1;
if (l<=mid) upturn(l,r,ls);
if (r>mid) upturn(l,r,rs);
return (void)(t[x]=up(t[ls],t[rs]));
}
inline int asks(int l,int r,int x)
{
down(x);
if (l<=lb&&rb<=r) return t[x].s[1];
int mid=(lb+rb)>>1;int ans=0;
if (l<=mid) ans+=asks(l,r,ls);
if (r>mid) ans+=asks(l,r,rs);
return ans;
}
inline Seg ask1(int l,int r,int x)
{
down(x);
if (l<=lb&&rb<=r) return t[x];
int mid=(lb+rb)>>1;Seg jun,er;
if (l<=mid) jun=ask1(l,r,ls);
if (r>mid) er=ask1(l,r,rs);
return up(jun,er);
}
signed main()
{
scanf("%d%d",&n,&m);
int fl,x,y;built(1,n,1);
while (m--)
{
scanf("%d%d%d",&fl,&x,&y);x++;y++;
if (fl==0) update(x,y,1,0);
else if (fl==1) update(x,y,1,1);
else if (fl==2) upturn(x,y,1);
else if (fl==3) printf("%d\n",asks(x,y,1));
else if (fl==4) printf("%d\n",ask1(x,y,1).o[2]);
}
return 0;
}