题意
对于一个$01$序列,有$5$种操作:
$0 \ a \ b$ 把$[a,b]$区间内的所有数全变成$0$
$1 \ a \ b$ 把$[a,b]$区间内的所有数全变成$1$
$2 \ a \ b$ 把$[a,b]$区间内的所有数全部取反
$3 \ a \ b$ 询问$[a,b]$区间内总共有多少个$1$
$4 \ a \ b$ 询问$[a,b]$区间内最多有多少个连续的$1$
对于每个询问,输出答案
数据范围:$1 \le n,m \le 100000$
题解
明显的线段树题
需要维护哪些东西?区间$1$的总数,连续$1$的最大个数,覆盖标记,取反标记
为了在取反后获得连续$1$的最大个数,还需要维护连续$0$的最大个数
因为询问的是连续的$1$,在进行区间合并的时候,需要考虑以下情况
- 左区间的值
- 右区间的值
- 左区间的右端点可以和右区间的左端点接上
这样,还需要额外维护一个区间从左/右端点开始的连续$1$个数
而合并这两个东西也有特殊的情况,以从左开始为例,从右开始类似
- 左区间的值
- 左区间满,合并后为左区间的值$+$右区间从左开始的连续$1$个数
而因为区间取反的存在,同样需要同时维护这样的连续$0$个数
inline node operator + (const node& x){
node res;
res.c=c+x.c;
res.l[0]=l[0];
res.l[1]=l[1];
if(s[0]==0)
res.l[1]+=x.l[1];
if(s[1]==0)
res.l[0]+=x.l[0];
res.r[0]=x.r[0];
res.r[1]=x.r[1];
if(x.s[0]==0)
res.r[1]+=r[1];
if(x.s[1]==0)
res.r[0]+=r[0];
res.s[0]=max(r[0]+x.l[0],max(s[0],x.s[0]));
res.s[1]=max(r[1]+x.l[1],max(s[1],x.s[1]));
return res;
}
下面是$pushdown$函数的写法
首先考虑两个标记的优先级问题:在区间覆盖后,区间取反会失效,所以优先处理区间覆盖;并在处理区间覆盖标记后,将区间取反标记置$0$
区间取反要交换维护的$0/1$的值,并将区间$1$个数更新为区间长度$-$区间$1$个数
inline void pushDown(int rt,int len){
if(T[rt].v!=-1){
T[ls].s[0]=T[ls].l[0]=T[ls].r[0]=(T[rt].v^1)*(len-(len>>1));
T[ls].c=T[ls].s[1]=T[ls].l[1]=T[ls].r[1]=T[rt].v*(len-(len>>1));
T[rs].s[0]=T[rs].l[0]=T[rs].r[0]=(T[rt].v^1)*(len>>1);
T[rs].c=T[rs].s[1]=T[rs].l[1]=T[rs].r[1]=T[rt].v*(len>>1);
T[ls].v=T[rs].v=T[rt].v;
T[ls].f=T[rs].f=0;
T[rt].v=-1;
}
if(T[rt].f){
T[ls].c=(len-(len>>1))-T[ls].c;
T[rs].c=(len>>1)-T[rs].c;
swap(T[ls].s[0],T[ls].s[1]);
swap(T[ls].l[0],T[ls].l[1]);
swap(T[ls].r[0],T[ls].r[1]);
swap(T[rs].s[0],T[rs].s[1]);
swap(T[rs].l[0],T[rs].l[1]);
swap(T[rs].r[0],T[rs].r[1]);
T[ls].f^=1;
T[rs].f^=1;
T[rt].f=0;
}
}
至此,本题复杂的操作完成,剩余部分与一般线段树无异
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ls rt<<1
#define rs rt<<1|1
const int N=100000+10;
int n,m,op,a,b;
bool p[N];
struct node{
int c,s[2],l[2],r[2];
int v;
bool f;
inline node():c(0),s{0,0},l{0,0},r{0,0},v(-1),f(0){}
inline node operator + (const node& x){
node res;
res.c=c+x.c;
res.l[0]=l[0];
res.l[1]=l[1];
if(s[0]==0)
res.l[1]+=x.l[1];
if(s[1]==0)
res.l[0]+=x.l[0];
res.r[0]=x.r[0];
res.r[1]=x.r[1];
if(x.s[0]==0)
res.r[1]+=r[1];
if(x.s[1]==0)
res.r[0]+=r[0];
res.s[0]=max(r[0]+x.l[0],max(s[0],x.s[0]));
res.s[1]=max(r[1]+x.l[1],max(s[1],x.s[1]));
return res;
}
} T[N<<2];
inline void pushUp(int rt){
T[rt]=T[ls]+T[rs];
}
inline void pushDown(int rt,int len){
if(T[rt].v!=-1){
T[ls].s[0]=T[ls].l[0]=T[ls].r[0]=(T[rt].v^1)*(len-(len>>1));
T[ls].c=T[ls].s[1]=T[ls].l[1]=T[ls].r[1]=T[rt].v*(len-(len>>1));
T[rs].s[0]=T[rs].l[0]=T[rs].r[0]=(T[rt].v^1)*(len>>1);
T[rs].c=T[rs].s[1]=T[rs].l[1]=T[rs].r[1]=T[rt].v*(len>>1);
T[ls].v=T[rs].v=T[rt].v;
T[ls].f=T[rs].f=0;
T[rt].v=-1;
}
if(T[rt].f){
T[ls].c=(len-(len>>1))-T[ls].c;
T[rs].c=(len>>1)-T[rs].c;
swap(T[ls].s[0],T[ls].s[1]);
swap(T[ls].l[0],T[ls].l[1]);
swap(T[ls].r[0],T[ls].r[1]);
swap(T[rs].s[0],T[rs].s[1]);
swap(T[rs].l[0],T[rs].l[1]);
swap(T[rs].r[0],T[rs].r[1]);
T[ls].f^=1;
T[rs].f^=1;
T[rt].f=0;
}
}
void build(int rt,int l,int r){
if(l==r){
T[rt].c=T[rt].s[1]=T[rt].l[1]=T[rt].r[1]=p[l];
T[rt].s[0]=T[rt].l[0]=T[rt].r[0]=p[l]^1;
return ;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushUp(rt);
}
void update(int rt,int l,int r,int L,int R,int k){
if(l>=L && r<=R){
if(k==-1){
T[rt].f^=1;
T[rt].c=(r-l+1)-T[rt].c;
swap(T[rt].s[0],T[rt].s[1]);
swap(T[rt].l[0],T[rt].l[1]);
swap(T[rt].r[0],T[rt].r[1]);
}
else{
T[rt].s[0]=T[rt].l[0]=T[rt].r[0]=(k^1)*(r-l+1);
T[rt].c=T[rt].s[1]=T[rt].l[1]=T[rt].r[1]=k*(r-l+1);
T[rt].v=k;
T[rt].f=0;
}
return ;
}
pushDown(rt,r-l+1);
int mid=l+r>>1;
if(L<=mid)
update(ls,l,mid,L,R,k);
if(R>mid)
update(rs,mid+1,r,L,R,k);
pushUp(rt);
}
node query(int rt,int l,int r,int L,int R){
if(l>=L && r<=R){
return T[rt];
}
pushDown(rt,r-l+1);
node res;
int mid=l+r>>1;
if(L<=mid)
res=res+query(ls,l,mid,L,R);
if(R>mid)
res=res+query(rs,mid+1,r,L,R);
pushUp(rt);
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&p[i]);
build(1,1,n);
for(;m--;){
scanf("%d%d%d",&op,&a,&b);
a++,b++;
switch(op){
case 0:update(1,1,n,a,b,0);break;
case 1:update(1,1,n,a,b,1);break;
case 2:update(1,1,n,a,b,-1);break;
case 3:printf("%d\n",query(1,1,n,a,b).c);break;
case 4:printf("%d\n",query(1,1,n,a,b).s[1]);break;
}
}
return 0;
}