题意
给定一个长度为
n
n
的 串,完成
m
m
个操作,操作分 种。
0.
0.
x
x
把区间
[x,y]
[
x
,
y
]
全部赋值为
0
0
x
x
把区间
[x,y]
[
x
,
y
]
全部赋值为
1
1
x
x
对区间
[x,y]
[
x
,
y
]
取反,即
0
0
变 ,
1
1
变
3.
3.
x
x
询问区间
[x,y]
[
x
,
y
]
内总共有多少个
1
1
x
x
询问区间
[x,y]
[
x
,
y
]
内最多有多少个连续的
1
1
思路
这种区间修改查询的问题,线段树是最适合的。先观察询问,总共有多少个
1
1
的询问,只用存储每个节点区间中 的个数,再累加上来即可。而最多连续多少个
1
1
的询问,先考虑把问题化小,一个区间中最多连续 的个数莫过于以下三种:左子区间最多连续
1
1
的个数(都在左边),右子区间最多连续 的个数(都在右边),以左子区间最右端向左的最多连续
1
1
的个数加右子区间向右的最多连续个数(横跨左右)。所以,对于一个区间我们要维护的信息有: 的个数,最多连续
1
1
的个数,最左端向右最多连续 的个数,最右端向左最多
1
1
的个数。
再看看修改。整体赋值的操作用一个代表赋值的标记就可以实现,而整体取反,再加一个代表取反的标记也可以实现(由于取反的存在,上述维护信息还要多维护关于 的信息)。但是再处理多标记的线段树时,一定要考虑标记之间是否会互相影响。比如这题,如果一个区间先赋值,再取反,赋值标记也应该取反;先取反,再赋值,取反标记应直接消失。
代码
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define N 100003
typedef long long LL;
using namespace std;
struct node
{
int L,R,ls[2],rs[2],as[2],sum[2],tag;
bool re;
node operator +(const node &_)const
{
node res;
res.L=L,res.R=_.R,res.tag=-1,res.re=0;
FOR(i,0,1)
{
res.ls[i]=(ls[i]==R-L+1?ls[i]+_.ls[i]:ls[i]);
res.rs[i]=(_.rs[i]==_.R-_.L+1?_.rs[i]+rs[i]:_.rs[i]);
res.as[i]=max(max(as[i],_.as[i]),rs[i]+_.ls[i]);
res.sum[i]=sum[i]+_.sum[i];
}
return res;
}
void tag_up(int val)
{
re=0,tag=val;
FOR(i,0,1)ls[i]=rs[i]=as[i]=sum[i]=(tag==i)*(R-L+1);
return;
}
void re_up()
{
re^=1;
if(tag==0)tag=1;
else if(tag==1)tag=0;
swap(ls[0],ls[1]),swap(rs[0],rs[1]),swap(as[0],as[1]),swap(sum[0],sum[1]);
return;
}
};
struct SegmentTree
{
node nd[N<<2];
void build(int k,int L,int R,int *arr)
{
if(L==R)
{
nd[k].L=nd[k].R=L;
FOR(i,0,1)nd[k].ls[i]=nd[k].rs[i]=nd[k].as[i]=nd[k].sum[i]=(arr[L]==i);
nd[k].tag=-1;
nd[k].re=0;
return;
}
build(k<<1,L,L+R>>1,arr);
build(k<<1|1,(L+R>>1)+1,R,arr);
nd[k]=nd[k<<1]+nd[k<<1|1];
return;
}
void push_down(int k)
{
if(nd[k].re)
{
nd[k<<1].re_up();
nd[k<<1|1].re_up();
nd[k].re=0;
}
if(!~nd[k].tag)return;
nd[k<<1].tag_up(nd[k].tag);
nd[k<<1|1].tag_up(nd[k].tag);
nd[k].tag=-1;
return;
}
void update(int k,int L,int R,int val)
{
if(L<=nd[k].L&&nd[k].R<=R)
{
if(val!=2)nd[k].tag_up(val);
else nd[k].re_up();
return;
}
push_down(k);
int mid=nd[k].L+nd[k].R>>1;
if(L<=mid)update(k<<1,L,R,val);
if(mid<R)update(k<<1|1,L,R,val);
nd[k]=nd[k<<1]+nd[k<<1|1];
return;
}
node query(int k,int L,int R)
{
if(L<=nd[k].L&&nd[k].R<=R)
return nd[k];
push_down(k);
int mid=nd[k].L+nd[k].R>>1;
if(R<=mid)return query(k<<1,L,R);
else if(mid<L)return query(k<<1|1,L,R);
else return query(k<<1,L,R)+query(k<<1|1,L,R);
}
}ST;
int a[N];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
FOR(i,1,n)scanf("%d",&a[i]);
ST.build(1,1,n,a);
FOR(i,1,m)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
x++,y++;
if(op>=0&&op<=2)
ST.update(1,x,y,op);
else if(op==3)printf("%d\n",ST.query(1,x,y).sum[1]);
else printf("%d\n",ST.query(1,x,y).as[1]);
}
}
return 0;
}