此题中维护操作略多,先说下思路
有两种更新操作set和update分别为设置[a,b]为0或1和求[a,b]反;
1.每次set操作时看是否是[a,b]覆盖区间,不是则查看是否此节点有set(1)或set(0)的标志,如果有的话,需要
把这个set标志pushdown到L(t),R(t),然后再把[a,b]的取反标志f,pushdown下去,然后递归查找左右子树。
如果【a,b]是覆盖区间,那么直接设置set标志,并把取反标志设0,(因为此时下边区间是否取反已经无所谓了)
2.每次update取反时差不多,需要把有set标志的先pushdown然后pushdown取反标志。
因为一个节点如果同时有两个标志时,一定表示这个节点先进行了set然后才取反,所以pushdown的时候先push set标志然后是取反标志。
假设是标志设置顺序是先取反,那么后来的set标志时后吧f清零(每set一个覆盖区间,相应区间的f=0)所以只可能是先set,再取反
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<cmath>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MAX 100010
using namespace std;
void Swap(int t);
void upwb(int t);
void uplen(int t);
void setdown(int t);
void setdowncover(int t);
void build(int t,int l, int r);
void set(int t,int l,int r,int val);
int querysum(int t,int l,int r);
void update(int t,int l,int r);
int queryblen(int t,int l,int r);
struct node
{
int l,r;
int wr,wl,br,bl;
int wlen,blen;
int cover;
int sum;
bool f;
}a[MAX*3];
int number[MAX];
int main()
{
int t,m,n,i,l,r,p;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%d",&number[i]);
}
build(1,0,n-1);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&p,&l,&r);
switch(p)
{
case 0:;
case 1:set(1,l,r,p);break;
case 2:update(1,l,r);break;
case 3:printf("%d\n",querysum(1,l,r));break;
case 4:printf("%d\n",queryblen(1,l,r));
}
}
}
}
void Swap(int t)
{
swap(a[t].wlen,a[t].blen);
swap(a[t].wl,a[t].bl);
swap(a[t].wr,a[t].br);
a[t].sum=a[t].r-a[t].l+1-a[t].sum;
}
void upwb(int t)
{
int ll=a[L(t)].r-a[L(t)].l+1;
a[t].wl=a[L(t)].wl+(a[L(t)].wl==ll?a[R(t)].wl:0);
a[t].bl=a[L(t)].bl+(a[L(t)].bl==ll?a[R(t)].bl:0);
ll=a[R(t)].r-a[R(t)].l+1;
a[t].wr=a[R(t)].wr+(a[R(t)].wr==ll?a[L(t)].wr:0);
a[t].br=a[R(t)].br+(a[R(t)].br==ll?a[L(t)].br:0);
a[t].wlen=max(max(a[L(t)].wlen,a[R(t)].wlen),a[L(t)].wr+a[R(t)].wl);
a[t].blen=max(max(a[L(t)].blen,a[R(t)].blen),a[L(t)].br+a[R(t)].bl);
}
void uplen(int t)
{
if(a[t].cover>0)
{
a[t].sum=a[t].r-a[t].l+1;
a[t].wlen=a[t].wl=a[t].wr=0;
a[t].blen=a[t].bl=a[t].br=a[t].sum;
return;
}
if(a[t].cover==0)
{
a[t].sum=0;
a[t].wlen=a[t].r-a[t].l+1;
a[t].wr=a[t].wl=a[t].wlen;
a[t].blen=a[t].br=a[t].bl=0;
return ;
}
a[t].sum=a[L(t)].sum+a[R(t)].sum;
upwb(t);
}
void setdown(int t)
{
if(a[t].f)
{
a[L(t)].f=!a[L(t)].f;
a[R(t)].f=!a[R(t)].f;
a[t].f=!a[t].f;
Swap(L(t));
Swap(R(t));
}
}
void setdowncover(int t)
{
a[L(t)].cover=a[t].cover;
a[R(t)].cover=a[t].cover;
a[t].cover=-1;
uplen(L(t));
uplen(R(t));
a[L(t)].f=0;
a[R(t)].f=0;
}
void build(int t,int l, int r)
{
a[t].l=l;
a[t].r=r;
a[t].f=0;
a[t].cover=-1;
if(l==r)
{
a[t].blen=number[l];
a[t].wlen=1-a[t].blen;
a[t].wr=a[t].wl=a[t].wlen;
a[t].bl=a[t].br=a[t].blen;
a[t].sum=number[l];
return ;
}
int mid=(l+r)>>1;
build(L(t),l,mid);
build(R(t),mid+1,r);
uplen(t);
}
void set(int t,int l,int r,int val)
{
if(l<=a[t].l&&a[t].r<=r)
{
a[t].cover=val;
a[t].f=0;
uplen(t);
return ;
}
if(a[t].cover!=-1)
{
setdowncover(t);
a[L(t)].f=0;
a[R(t)].f=0;
}
setdown(t);
int mid=(a[t].l+a[t].r)>>1;
if(l<=mid)
set(L(t),l,r,val);
if(r>mid)
set(R(t),l,r,val);
uplen(t);
}
int querysum(int t,int l,int r)
{
if(l<=a[t].l&&a[t].r<=r)
{
return a[t].sum;
}
if(a[t].cover!=-1)
{
setdowncover(t);
}
setdown(t);
int mid=(a[t].l+a[t].r)>>1;
int ans=0;
if (l<=mid)
ans+=querysum(L(t),l,r);
if(r>mid)
ans+=querysum(R(t),l,r);
uplen(t);
return ans;
}
void update(int t,int l,int r)
{
if(l<=a[t].l&&a[t].r<=r)
{
a[t].f=!a[t].f;
Swap(t);
return ;
}
if(a[t].cover!=-1)
{
setdowncover(t);
}
setdown(t);
int mid=(a[t].l+a[t].r)>>1;
if(l<=mid)
update(L(t),l,r);
if(r>mid)
update(R(t),l,r);
uplen(t);
}
int queryblen(int t,int l,int r)
{
if(l<=a[t].l&&a[t].r<=r)
{
return a[t].blen;
}
if(a[t].cover!=-1)
{
setdowncover(t);
}
setdown(t);
int mid=(a[t].l+a[t].r)>>1;
int ans=0;
int p=0;
int q=0;
if(l<=mid)
{
ans=max(ans,queryblen(L(t),l,r));
if(r>=a[L(t)].r)
p=min(a[L(t)].br,a[L(t)].r-l+1);
}
if(r>mid)
{
ans=max(ans,queryblen(R(t),l,r));
if(l<=a[R(t)].l)
q=min(a[R(t)].bl,r-a[R(t)].l+1);
}
ans=max(ans,p+q);
uplen(t);
return ans;
}