【题目】
题目描述:
lxhgww 最近收到了一个 01 01 01 序列,序列里面包含了 n n n 个数,这些数要么是 0 0 0,要么是 1 1 1,现在对于这个序列有五种变换操作和询问操作:
-
0 0 0 a a a b b b:把 [ a a a , b b b ] 区间内的所有数全变成 0 0 0
-
1 1 1 a a a b b b:把 [ a a a , b b b ] 区间内的所有数全变成 1 1 1
-
2 2 2 a a a b b b:把 [ a a a , b b b ] 区间内的所有数全部取反,也就是说把所有的 0 0 0 变成 1 1 1,把所有的 1 1 1 变成 0 0 0
-
3 3 3 a a a b b b:询问 [ a a a , b b b ] 区间内总共有多少个 1 1 1
-
4 4 4 a a a b b b:询问 [ a a a , b b b ] 区间内最多有多少个连续的 1 1 1
对于每一种询问操作,lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?
输入格式:
输入数据第一行包括 2 2 2 个数, n n n 和 m m m,分别表示序列的长度和操作数目
第二行包括 n n n 个数,表示序列的初始状态
接下来 m m m 行,每行 3 3 3 个数, o p , a , b op, a, b op,a,b,( 0 0 0 ≤ o p op op ≤ 4 4 4, 0 0 0 ≤ a a a ≤ b b b < n n n)表示对于区间 [ a a a , b b b ] 执行标号为 o p op op 的操作
输出格式:
对于每一个询问操作,输出一行,包括 1 1 1 个数,表示其对应的答案
样例数据:
输入
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
输出
5
2
6
5
说明:
【数据范围】
对于
30
%
30\%
30% 的数据,
1
1
1 ≤
n
,
m
n, m
n,m ≤
1000
1000
1000
对于
100
%
100\%
100% 的数据,
1
1
1 ≤
n
,
m
n, m
n,m ≤
100000
100000
100000
【分析】
题解:线段树,支持区间覆盖,区间取反,区间求和,区间求最大连续子段
其实这几个操作都是基础的操作,但由于代码能力较弱,硬是调了很久
应该算是一道好题吧,比较综合,把很多东西都一次就考到了
代码还是比较简洁,不算很长,但还是有很多细节
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int a[N];
struct node
{
int L[2],R[2],Max[2],sum[2],len,change,cover;
}Seg[N<<2];
node update(node left,node right)
{
node root;
root.change=0,root.cover=-1;
root.len=left.len+right.len;
for(int i=0;i<=1;++i)
{
root.sum[i]=left.sum[i]+right.sum[i];
root.L[i]=(left.L[i]==left.len?left.L[i]+right.L[i]:left.L[i]);
root.R[i]=(right.R[i]==right.len?right.R[i]+left.R[i]:right.R[i]);
root.Max[i]=max(max(left.Max[i],right.Max[i]),left.R[i]+right.L[i]);
}
return root;
}
void Build(int root,int l,int r)
{
if(l==r)
{
Seg[root].change=0,Seg[root].cover=-1,Seg[root].len=1;
Seg[root].L[a[l]]=Seg[root].R[a[l]]=Seg[root].Max[a[l]]=Seg[root].sum[a[l]]=1;
return;
}
int mid=(l+r)>>1;
Build(root<<1,l,mid);
Build(root<<1|1,mid+1,r);
Seg[root]=update(Seg[root<<1],Seg[root<<1|1]);
}
void Cover(int root,int l,int r,int val)
{
Seg[root].cover=val;Seg[root].change=0;
Seg[root].L[val]=Seg[root].R[val]=Seg[root].Max[val]=Seg[root].sum[val]=r-l+1;
Seg[root].L[val^1]=Seg[root].R[val^1]=Seg[root].Max[val^1]=Seg[root].sum[val^1]=0;
}
void Change(int root)
{
Seg[root].change^=1;
swap(Seg[root].L[0],Seg[root].L[1]);
swap(Seg[root].R[0],Seg[root].R[1]);
swap(Seg[root].sum[0],Seg[root].sum[1]);
swap(Seg[root].Max[0],Seg[root].Max[1]);
}
void Pushdown(int root,int l,int r,int mid)
{
if(Seg[root].cover!=-1) Cover(root<<1,l,mid,Seg[root].cover),Cover(root<<1|1,mid+1,r,Seg[root].cover);
if(Seg[root].change) Change(root<<1),Change(root<<1|1);
Seg[root].cover=-1,Seg[root].change=0;
}
void Modify(int root,int l,int r,int x,int y,int k)
{
if(l>=x&&r<=y)
{
Cover(root,l,r,k);
return;
}
int mid=(l+r)>>1;
Pushdown(root,l,r,mid);
if(x<=mid) Modify(root<<1,l,mid,x,y,k);
if(y>mid) Modify(root<<1|1,mid+1,r,x,y,k);
Seg[root]=update(Seg[root<<1],Seg[root<<1|1]);
}
void Negate(int root,int l,int r,int x,int y)
{
if(l>=x&&r<=y)
{
Change(root);
return;
}
int mid=(l+r)>>1;
Pushdown(root,l,r,mid);
if(x<=mid) Negate(root<<1,l,mid,x,y);
if(y>mid) Negate(root<<1|1,mid+1,r,x,y);
Seg[root]=update(Seg[root<<1],Seg[root<<1|1]);
}
node Query(int root,int l,int r,int x,int y)
{
if(l>=x&&r<=y)
return Seg[root];
int mid=(l+r)>>1;
Pushdown(root,l,r,mid);
if(y<=mid) return Query(root<<1,l,mid,x,y);
if(x>mid) return Query(root<<1|1,mid+1,r,x,y);
return update(Query(root<<1,l,mid,x,y),Query(root<<1|1,mid+1,r,x,y));
}
int main()
{
int n,m,i,s,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
scanf("%d",&a[i]);
Build(1,1,n);
for(i=1;i<=m;++i)
{
scanf("%d%d%d",&s,&x,&y);x++,y++;
if(s==0) Modify(1,1,n,x,y,0);
if(s==1) Modify(1,1,n,x,y,1);
if(s==2) Negate(1,1,n,x,y);
if(s==3) printf("%d\n",Query(1,1,n,x,y).sum[1]);
if(s==4) printf("%d\n",Query(1,1,n,x,y).Max[1]);
}
return 0;
}