浅调两个钟,终于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=1if(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;
}