原题链接:https://www.luogu.com.cn/problem/P2572
序列操作
题目描述
lxhgww 最近收到了一个 01 01 01 序列,序列里面包含了 n n n 个数,下标从 0 0 0 开始。这些数要么是 0 0 0,要么是 1 1 1,现在对于这个序列有五种变换操作和询问操作:
0 l r
把 [ l , r ] [l, r] [l,r] 区间内的所有数全变成 0 0 0
1 l r
把 [ l , r ] [l, r] [l,r] 区间内的所有数全变成 1 1 1
2 l r
把 [ l , r ] [l,r] [l,r] 区间内的所有数全部取反,也就是说把所有的 0 0 0 变成 1 1 1,把所有的 1 1 1 变成 0 0 0
3 l r
询问 [ l , r ] [l, r] [l,r] 区间内总共有多少个 1 1 1
4 l r
询问 [ l , r ] [l, r] [l,r] 区间内最多有多少个连续的 1 1 1
对于每一种询问操作,lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?
输入格式
第一行两个正整数 n , m n,m n,m,表示序列长度与操作个数。
第二行包括 n n n 个数,表示序列的初始状态。
接下来 m m m 行,每行三个整数,表示一次操作。
输出格式
对于每一个询问操作,输出一行一个数,表示其对应的答案。
输入输出样例
输入 #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
输出 #1
5
2
6
5
说明/提示
【数据范围】
对于 30 % 30\% 30% 的数据, 1 ≤ n , m ≤ 1000 1\le n,m \le 1000 1≤n,m≤1000;
对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 1 0 5 1\le n,m \le 10^5 1≤n,m≤105 。
题解
上一题的升级版,因为区间取反操作的存在,我们必须同时记录 0 0 0和 1 1 1的包含左端点最长序列、包含右端点最长序列和整个区间最长序列,维护类似。又因为要求区间内 1 1 1的数量,所以还要维护一个区间和。
相较于上一道题,本题多了区间取反标记。因为区间赋值时,之前的区间取反标记无意义;而区间取反时,区间赋值标记还会相应取反,所以在打标记的时候,区间取反标记一定是在区间赋值标记后传下来的,即在取反标记传入的时候赋值标记已经对应的改变了。所以在下传标记的时候,要先传取反标记,再传赋值标记(举例:区间赋 0 0 0之后再区间取反相当于区间赋 1 1 1,这时候虽然节点里有两个标记,但是区间取反标记已经没意义里,所以我们下传的时候需要先下传取反标记,再传赋值标记直接覆盖掉取反标记)。
其实还有一种更好理解的写法:打取反标记的时候不改变赋值标记,下传的时候直接按照原本的“先赋值,再取反”标记顺序下传。当然也可以在传取反标记的时候检查一下该节点有无赋值标记,有则修改赋值标记(相当于合并了赋值标记和取反标记),总之写法很多,自己能理解就好。
对照代码更好理解。
代码
第一种写法:
#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=1e5+5;
struct node{
int le,ri,llen[2],rlen[2],mlen[2],sum;
bool clear,fill,rev;
}tree[M<<2];
int n,m,que[M];
void up(int v,int p)
{
tree[v].llen[p]=(tree[ls].llen[p]==tree[ls].ri-tree[ls].le+1)?tree[ls].llen[p]+tree[rs].llen[p]:tree[ls].llen[p];
tree[v].rlen[p]=(tree[rs].rlen[p]==tree[rs].ri-tree[rs].le+1)?tree[rs].rlen[p]+tree[ls].rlen[p]:tree[rs].rlen[p];
tree[v].mlen[p]=max(tree[ls].rlen[p]+tree[rs].llen[p],max(tree[ls].mlen[p],tree[rs].mlen[p]));
}
void up(int v)
{
up(v,0),up(v,1);
tree[v].sum=tree[ls].sum+tree[rs].sum;
}
void push_fill(int v,int p)
{
tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=tree[v].ri-tree[v].le+1;
}
void push_clear(int v,int p)
{
tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=0;
}
void push_rev(int v)
{
swap(tree[v].llen[0],tree[v].llen[1]);
swap(tree[v].rlen[0],tree[v].rlen[1]);
swap(tree[v].mlen[0],tree[v].mlen[1]);
tree[v].sum=tree[v].ri-tree[v].le+1-tree[v].sum;
tree[v].rev^=1;
if(tree[v].fill||tree[v].clear)swap(tree[v].fill,tree[v].clear);
}
void down(int v)
{
if(tree[v].rev)
{
push_rev(ls),push_rev(rs);
tree[v].rev=0;
}
if(tree[v].clear)
{
push_clear(ls,1),push_fill(ls,0);
push_clear(rs,1),push_fill(rs,0);
tree[ls].clear=1,tree[ls].fill=tree[ls].rev=0;
tree[rs].clear=1,tree[rs].fill=tree[rs].rev=0;
tree[ls].sum=tree[rs].sum=0;
tree[v].clear=0;
}
if(tree[v].fill)
{
push_clear(ls,0),push_fill(ls,1);
push_clear(rs,0),push_fill(rs,1);
tree[ls].fill=1,tree[ls].clear=tree[ls].rev=0;
tree[rs].fill=1,tree[rs].clear=tree[rs].rev=0;
tree[ls].sum=tree[ls].ri-tree[ls].le+1;
tree[rs].sum=tree[rs].ri-tree[rs].le+1;
tree[v].fill=0;
}
}
void build(int v,int le,int ri)
{
tree[v].le=le,tree[v].ri=ri;
if(le==ri)
{
tree[v].llen[que[le]]=tree[v].rlen[que[le]]=tree[v].mlen[que[le]]=1;
tree[v].sum=que[le];
return;
}
int mid=le+ri>>1;
build(ls,le,mid),build(rs,mid+1,ri);
up(v);
}
void fill(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)
{
tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=0;
tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=tree[v].ri-tree[v].le+1;
tree[v].fill=1,tree[v].clear=tree[v].rev=0;
return;
}
down(v);
int mid=tree[v].le+tree[v].ri>>1;
if(le<=mid)fill(ls,le,ri);
if(mid<ri)fill(rs,le,ri);
up(v);
}
void clear(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)
{
tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=0;
tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=tree[v].ri-tree[v].le+1;
tree[v].clear=1,tree[v].fill=tree[v].rev=0;
return;
}
down(v);
int mid=tree[v].le+tree[v].ri>>1;
if(le<=mid)clear(ls,le,ri);
if(mid<ri)clear(rs,le,ri);
up(v);
}
void rev(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)
{
push_rev(v);
return;
}
down(v);
int mid=tree[v].le+tree[v].ri>>1;
if(le<=mid)rev(ls,le,ri);
if(mid<ri)rev(rs,le,ri);
up(v);
}
int asksum(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].sum;
down(v);
int mid=tree[v].le+tree[v].ri>>1,r=0;
if(le<=mid)r=asksum(ls,le,ri);
if(mid<ri)r+=asksum(rs,le,ri);
return r;
}
int asklen(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].mlen[1];
down(v);
int mid=tree[v].le+tree[v].ri>>1,r=min(tree[rs].le+tree[rs].llen[1]-1,ri)-max(tree[ls].ri-tree[ls].rlen[1]+1,le)+1;
if(le<=mid)r=max(r,asklen(ls,le,ri));
if(mid<ri)r=max(r,asklen(rs,le,ri));
return r;
}
void in()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&que[i]);
}
void ac()
{
build(1,1,n);
for(int i=1,op,a,b;i<=m;++i)
{
scanf("%d%d%d",&op,&a,&b);
++a,++b;
if(!op)clear(1,a,b);
else if(op==1)fill(1,a,b);
else if(op==2)rev(1,a,b);
else if(op==3)printf("%d\n",asksum(1,a,b));
else printf("%d\n",asklen(1,a,b));
}
}
int main()
{
in(),ac();
//system("pause");
}
第二种写法:
#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=1e5+5;
struct node{
int le,ri,llen[2],rlen[2],mlen[2],sum;
bool clear,fill,rev;
}tree[M<<2];
int n,m,que[M];
void up(int v,int p)
{
tree[v].llen[p]=(tree[ls].llen[p]==tree[ls].ri-tree[ls].le+1)?tree[ls].llen[p]+tree[rs].llen[p]:tree[ls].llen[p];
tree[v].rlen[p]=(tree[rs].rlen[p]==tree[rs].ri-tree[rs].le+1)?tree[rs].rlen[p]+tree[ls].rlen[p]:tree[rs].rlen[p];
tree[v].mlen[p]=max(tree[ls].rlen[p]+tree[rs].llen[p],max(tree[ls].mlen[p],tree[rs].mlen[p]));
}
void up(int v)
{
up(v,0),up(v,1);
tree[v].sum=tree[ls].sum+tree[rs].sum;
}
void push_fill(int v,int p)
{
tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=tree[v].ri-tree[v].le+1;
}
void push_clear(int v,int p)
{
tree[v].llen[p]=tree[v].rlen[p]=tree[v].mlen[p]=0;
}
void push_rev(int v)
{
swap(tree[v].llen[0],tree[v].llen[1]);
swap(tree[v].rlen[0],tree[v].rlen[1]);
swap(tree[v].mlen[0],tree[v].mlen[1]);
tree[v].sum=tree[v].ri-tree[v].le+1-tree[v].sum;
tree[v].rev^=1;
//if(tree[v].fill||tree[v].clear)swap(tree[v].fill,tree[v].clear);
}
void down(int v)
{
if(tree[v].clear)
{
push_clear(ls,1),push_fill(ls,0);
push_clear(rs,1),push_fill(rs,0);
tree[ls].clear=1,tree[ls].fill=tree[ls].rev=0;
tree[rs].clear=1,tree[rs].fill=tree[rs].rev=0;
tree[ls].sum=tree[rs].sum=0;
tree[v].clear=0;
}
if(tree[v].fill)
{
push_clear(ls,0),push_fill(ls,1);
push_clear(rs,0),push_fill(rs,1);
tree[ls].fill=1,tree[ls].clear=tree[ls].rev=0;
tree[rs].fill=1,tree[rs].clear=tree[rs].rev=0;
tree[ls].sum=tree[ls].ri-tree[ls].le+1;
tree[rs].sum=tree[rs].ri-tree[rs].le+1;
tree[v].fill=0;
}
if(tree[v].rev)
{
push_rev(ls),push_rev(rs);
tree[v].rev=0;
}
}
void build(int v,int le,int ri)
{
tree[v].le=le,tree[v].ri=ri;
if(le==ri)
{
tree[v].llen[que[le]]=tree[v].rlen[que[le]]=tree[v].mlen[que[le]]=1;
tree[v].sum=que[le];
return;
}
int mid=le+ri>>1;
build(ls,le,mid),build(rs,mid+1,ri);
up(v);
}
void fill(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)
{
tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=0;
tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=tree[v].ri-tree[v].le+1;
tree[v].fill=1,tree[v].clear=tree[v].rev=0;
return;
}
down(v);
int mid=tree[v].le+tree[v].ri>>1;
if(le<=mid)fill(ls,le,ri);
if(mid<ri)fill(rs,le,ri);
up(v);
}
void clear(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)
{
tree[v].llen[1]=tree[v].rlen[1]=tree[v].mlen[1]=tree[v].sum=0;
tree[v].llen[0]=tree[v].rlen[0]=tree[v].mlen[0]=tree[v].ri-tree[v].le+1;
tree[v].clear=1,tree[v].fill=tree[v].rev=0;
return;
}
down(v);
int mid=tree[v].le+tree[v].ri>>1;
if(le<=mid)clear(ls,le,ri);
if(mid<ri)clear(rs,le,ri);
up(v);
}
void rev(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)
{
push_rev(v);
return;
}
down(v);
int mid=tree[v].le+tree[v].ri>>1;
if(le<=mid)rev(ls,le,ri);
if(mid<ri)rev(rs,le,ri);
up(v);
}
int asksum(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].sum;
down(v);
int mid=tree[v].le+tree[v].ri>>1,r=0;
if(le<=mid)r=asksum(ls,le,ri);
if(mid<ri)r+=asksum(rs,le,ri);
return r;
}
int asklen(int v,int le,int ri)
{
if(le<=tree[v].le&&tree[v].ri<=ri)return tree[v].mlen[1];
down(v);
int mid=tree[v].le+tree[v].ri>>1,r=min(tree[rs].le+tree[rs].llen[1]-1,ri)-max(tree[ls].ri-tree[ls].rlen[1]+1,le)+1;
if(le<=mid)r=max(r,asklen(ls,le,ri));
if(mid<ri)r=max(r,asklen(rs,le,ri));
return r;
}
void in()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&que[i]);
}
void ac()
{
build(1,1,n);
for(int i=1,op,a,b;i<=m;++i)
{
scanf("%d%d%d",&op,&a,&b);
++a,++b;
if(!op)clear(1,a,b);
else if(op==1)fill(1,a,b);
else if(op==2)rev(1,a,b);
else if(op==3)printf("%d\n",asksum(1,a,b));
else printf("%d\n",asklen(1,a,b));
}
}
int main()
{
in(),ac();
//system("pause");
}