一看以为是线段树水题,写起来发现好像询问4比较麻烦,调了好久。。
对每个线段树节点维护sum为区间内1的个数,ml0、mr0表示左右的最长连续0长度,ml1,mr1同理,m0、m1为区间内连续0/1的最大长度,合并信息的时候用ml0、mr0、ml1,mr1来更新m0、m1,就和维护数列那题一样。。这里要注意合并时维护ml1,mr1、ml0、mr0的时候要考虑能不能延长到另半个区间去,就像下图一样:
修改的时候打标记就是了,注意的地方就是如果有全0/1的标记打上去其他原来的标记都要清空。。
询问3好说,我就不讲了。。询问4比较麻烦,要将答案作为一个线段树节点一样上传,然后像线段树节点合并一样合并,其实也好搞。。
#include<cstdio>
#include<iostream>
#define N 400005
using namespace std;
int n,m,i,nd=0,qd,root,opt,L,R,a[N],c[N][2],l[N],r[N],ml0[N],ml1[N],mr0[N],mr1[N],m1[N],m0[N],sum[N],tag0[N],tag1[N],rev[N];
void update(int x)
{
int lc=c[x][0],rc=c[x][1];
ml0[x]=ml0[lc];ml1[x]=ml1[lc];
mr0[x]=mr0[rc];mr1[x]=mr1[rc];
if (ml0[lc]==r[lc]-l[lc]+1) ml0[x]=ml0[lc]+ml0[rc];
if (ml1[lc]==r[lc]-l[lc]+1) ml1[x]=ml1[lc]+ml1[rc];
if (mr0[rc]==r[rc]-l[rc]+1) mr0[x]=mr0[rc]+mr0[lc];
if (mr1[rc]==r[rc]-l[rc]+1) mr1[x]=mr1[rc]+mr1[lc];
m1[x]=max(mr1[lc]+ml1[rc],max(m1[lc],m1[rc]));
m0[x]=max(mr0[lc]+ml0[rc],max(m0[lc],m0[rc]));
sum[x]=sum[lc]+sum[rc];
}
void mark0(int x)
{
tag0[x]=1;tag1[x]=0;rev[x]=0;
ml0[x]=mr0[x]=m0[x]=r[x]-l[x]+1;
ml1[x]=mr1[x]=m1[x]=sum[x]=0;
}
void mark1(int x)
{
tag1[x]=1;tag0[x]=0;rev[x]=0;
ml0[x]=mr0[x]=m0[x]=0;
ml1[x]=mr1[x]=m1[x]=sum[x]=r[x]-l[x]+1;
}
void markr(int x)
{
rev[x]^=1;
swap(ml0[x],ml1[x]);swap(mr0[x],mr1[x]);
swap(m0[x],m1[x]);
sum[x]=r[x]-l[x]+1-sum[x];
}
void down(int x)
{
if (tag0[x]) mark0(c[x][0]),mark0(c[x][1]),tag0[x]=0;
if (tag1[x]) mark1(c[x][0]),mark1(c[x][1]),tag1[x]=0;
if (rev[x]) markr(c[x][0]),markr(c[x][1]),rev[x]=0;
}
void build(int &x,int ll,int rr)
{
x=++nd;
l[x]=ll;r[x]=rr;
tag0[x]=tag1[x]=rev[x]=0;
if (ll==rr)
{
c[x][0]=c[x][1]=0;
ml0[x]=mr0[x]=m0[x]=(a[ll]==0);
ml1[x]=mr1[x]=m1[x]=sum[x]=(a[ll]==1);
return;
}
int mid=(ll+rr)/2;
build(c[x][0],ll,mid);build(c[x][1],mid+1,rr);
update(x);
}
void change(int x,int ll,int rr,int k)
{
if (l[x]>rr||r[x]<ll) return;
down(x);
if (ll<=l[x]&&rr>=r[x])
{
if (k==0) mark0(x);else if (k==1) mark1(x);else markr(x);
return;
}
change(c[x][0],ll,rr,k);change(c[x][1],ll,rr,k);
update(x);
}
int query(int x,int ll,int rr)
{
if (l[x]>rr||r[x]<ll) return 0;
down(x);
if (ll<=l[x]&&rr>=r[x]) return sum[x];
return query(c[x][0],ll,rr)+query(c[x][1],ll,rr);
}
int query1(int x,int ll,int rr)
{
down(x);
if (ll==l[x]&&rr==r[x]) return x;
int mid=(l[x]+r[x])/2;
if (rr<=mid) return query1(c[x][0],ll,rr);
else if (ll>mid) return query1(c[x][1],ll,rr);
else
{
int ans=++qd;
c[ans][0]=query1(c[x][0],ll,mid);c[ans][1]=query1(c[x][1],mid+1,rr);
update(ans);
return ans;
}
}
int main()
{
freopen("1858.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) scanf("%d",&a[i]);
build(root,1,n);
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&opt,&L,&R);
if (opt==0||opt==1||opt==2) change(root,L+1,R+1,opt);
else
{
if (opt==3) printf("%d\n",query(root,L+1,R+1)); else qd=nd,printf("%d\n",m1[query1(root,L+1,R+1)]);
}
}
}