浅调两个钟,终于A掉了,还是不熟练啊
这道题是P4513 小白逛公园 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)的变种
维护的更多,可以说,在维护连续的1,实质上就是维护最大连续子段和。
0 l r
把 [l,r] 区间内的所有数全变成 0;1 l r
把 [l,r] 区间内的所有数全变成 1;2 l r
把 [l,r] 区间内的所有数全部取反,也就是说把所有的 0 变成 1,把所有的 1 变成 0;3 l r
询问 [l,r] 区间内总共有多少个 1;4 l r
询问 [l,r] 区间内最多有多少个连续的 1。
要进行如上的五种操作,我们考虑建立
1.len来记录区间长度(优化)。
2.考虑用tag来维护懒标记,tag=-1时没有操作,tag=0使执行0行为,1同样。
3.用rev记录是否反转(reverse简写)
4.用b,rb,lb,mb分别记录 区间中1个数 区间左边1连续个数 区间右边1连续个数 最大连续个数
(c同理)
代码如下(有注释)
// Problem:
// P2572 [SCOI2010] 序列操作
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2572
// Memory Limit: 128 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N];
#define ls u<<1
#define rs u<<1|1
#define endl '\n'
struct Tree{
int l,r;
int b,lb,rb,mb,c,lc,rc,mc;//1的区间个数 左边连续个数 右边连续个数 最大连续个数
int len,tag,rev;//-1 无 0 0 1 1
}tr[N*4];
void mo(int u,int op){
Tree &t=tr[u];//注意每个地方的t都是要引用的
if(op==0){
t.c=t.lc=t.rc=t.mc=t.len;//覆盖
t.b=t.lb=t.mb=t.rb=0;
t.rev=0;//要重置 覆盖掉了
t.tag=0;
}
if(op==1){
t.c=t.lc=t.rc=t.mc=0;
t.b=t.lb=t.mb=t.rb=t.len;
t.rev=0;//要重置 覆盖掉了
t.tag=1;
}
if(op==2){
swap(t.c,t.b);swap(t.rc,t.rb);//取反,所有的都直接交换即可
swap(t.lc,t.lb);swap(t.mc,t.mb);
t.rev^=1;
}
}
void pushup(Tree &t,Tree l,Tree r){//别忘了开引用
t.b=l.b+r.b;
t.c=l.c+r.c;
t.lb=l.c ? l.lb : l.lb+r.lb; //判断是否有非1的,两种处理方式
t.lc=l.b ? l.lc : l.lc+r.lc;
t.rb=r.c ? r.rb : l.rb+r.rb;
t.rc=r.b ? r.rc : l.rc+r.rc;
t.mb=max(max(l.mb,r.mb),l.rb+r.lb);
t.mc=max(max(l.mc,r.mc),l.rc+r.lc);
}
void pushdown(int u){
Tree &t=tr[u];
if(t.tag==0) mo(ls,0),mo(rs,0);
if(t.tag==1) mo(ls,1),mo(rs,1);
if(t.rev) mo(ls,2),mo(rs,2);
t.tag=-1;//重置
t.rev=0;//重置
}
void update(int u,int l,int r,int op){
if(l<=tr[u].l&&tr[u].r<=r){
mo(u,op);return;//直接操作
}
pushdown(u);//记得下传
int m=(tr[u].l+tr[u].r)>>1;
if(l<=m) update(ls,l,r,op);
if(r>m) update(rs,l,r,op);
pushup(tr[u],tr[ls],tr[rs]);
}
Tree query(int u,int l,int r){
if(l<=tr[u].l&&tr[u].r<=r){
return tr[u];
}
pushdown(u);
int m=(tr[u].l+tr[u].r)>>1;
if(r<=m) return query(ls,l,r);//这里与平常的写法是不同的
if(l>m) return query(rs,l,r);
Tree t;//开一个t结合一下
pushup(t,query(ls,l,m),query(rs,m+1,r));
return t;
}
void build(int u,int l,int r){
int t=a[l];
tr[u]={l,r,t,t,t,t,t^1,t^1,t^1,t^1,r-l+1,-1,0};//1^1=0 0^1=1
if(l==r) return;
int m=(l+r)>>1;
build(ls,l,m);
build(rs,m+1,r);
pushup(tr[u],tr[ls],tr[rs]);
}
int main(){
int n;cin>>n;int m;cin>>m;
for(int i=1;i<=n;++i) cin>>a[i];
build(1,1,n);
while(m--){
int x,y,z;cin>>x>>y>>z;
y++,z++;//右移一位方便运算
if(x<=2){
update(1,y,z,x);
}
else{
Tree t=query(1,y,z);
cout<<((x==3) ? (t.b) :(t.mb))<<endl;
}
}
return 0;
}