洛谷2572 【SCOI2010】序列操作(线段树)
传送门
【题目分析】
线段树大板题,主要就是靠码量和debug能力。。。
既然涉及到区间取反,那么同时记录0和1的信息。
对于0,1操作,打上区间覆盖标记即可。
对于2操作,打区间取反标记,但注意如果该区间已经打了区间覆盖标记,那么其实取反标记作用只是将0改为1,所以可以直接将区间取反标记赋为0,覆盖标记取亦或。
对于3操作,直接统计即可。
对于操作4,考虑两种情况:1.当前区间maxmid为区间长,那么可以取左右两区间的左右最长。2.否则直接取左边最长,右边最长再与中间作比较取最大值即可。
代码细节很多,调起来很难受qwq
【代码~】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int INF=0x3f3f3f3f;
int n,q,ans,maxx;
int a[MAXN];
struct Tree{
int l,r;
int maxl[2],maxr[2],mmid[2];
int cnt[2];
int cov;
int rev;
}tr[MAXN<<2];
int Read(){
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
void push_up(int root){
int mid=tr[root].l+tr[root].r>>1;
for(int i=0;i<2;++i){
tr[root].cnt[i]=tr[root<<1].cnt[i]+tr[root<<1|1].cnt[i];
tr[root].maxl[i]=tr[root<<1].maxl[i],tr[root].maxr[i]=tr[root<<1|1].maxr[i];
if(tr[root<<1].maxl[i]==mid-tr[root].l+1)
tr[root].maxl[i]+=tr[root<<1|1].maxl[i];
if(tr[root<<1|1].maxr[i]==tr[root].r-mid)
tr[root].maxr[i]+=tr[root<<1].maxr[i];
tr[root].mmid[i]=max(tr[root<<1].mmid[i],max(tr[root<<1|1].mmid[i],tr[root<<1].maxr[i]+tr[root<<1|1].maxl[i]));
}
}
void push_cov(int root,int key){
tr[root].cov=key;
for(int i=0;i<2;++i){
tr[root].cnt[i]=tr[root].maxl[i]=tr[root].maxr[i]=tr[root].mmid[i]=(key==i)?(tr[root].r-tr[root].l+1):0;
}
}
void push_rev(int root){
tr[root].rev^=1;
swap(tr[root].maxl[0],tr[root].maxl[1]);
swap(tr[root].maxr[0],tr[root].maxr[1]);
swap(tr[root].mmid[0],tr[root].mmid[1]);
swap(tr[root].cnt[0],tr[root].cnt[1]);
if(tr[root].cov!=-1){
tr[root].rev=0;
tr[root].cov^=1;
}
}
void push_down(int root){
if(tr[root].cov!=-1){
push_cov(root<<1,tr[root].cov);
push_cov(root<<1|1,tr[root].cov);
tr[root].cov=-1;
tr[root].rev=0;
}
if(tr[root].rev){
push_rev(root<<1);
push_rev(root<<1|1);
tr[root].rev=0;
}
}
void build(int root,int l,int r){
tr[root].l=l,tr[root].r=r;
tr[root].cov=-1;
if(l==r){
for(int i=0;i<2;++i){
tr[root].maxl[i]=tr[root].maxr[i]=tr[root].mmid[i]=(a[l]==i)?1:0;
tr[root].cnt[i]=(a[l]==i)?1:0;
}
return ;
}
int mid=l+r>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
push_up(root);
}
void update_cov(int root,int l,int r,int L,int R,int key){
if(l>R||r<L)
return ;
if(L<=l&&r<=R){
push_cov(root,key);
return ;
}
push_down(root);
int mid=l+r>>1;
if(R<=mid)
update_cov(root<<1,l,mid,L,R,key);
else{
if(L>mid)
update_cov(root<<1|1,mid+1,r,L,R,key);
else
update_cov(root<<1,l,mid,L,mid,key),update_cov(root<<1|1,mid+1,r,mid+1,R,key);
}
push_up(root);
}
void update_rev(int root,int l,int r,int L,int R){
if(l>R||r<L)
return ;
if(L<=l&&r<=R){
push_rev(root);
return ;
}
push_down(root);
int mid=l+r>>1;
if(R<=mid)
update_rev(root<<1,l,mid,L,R);
else{
if(L>mid)
update_rev(root<<1|1,mid+1,r,L,R);
else
update_rev(root<<1,l,mid,L,mid),update_rev(root<<1|1,mid+1,r,mid+1,R);
}
push_up(root);
}
int query_tot(int root,int l,int r,int L,int R){
if(l>R||r<L)
return 0;
if(L<=l&&r<=R){
return tr[root].cnt[1];
}
push_down(root);
int mid=l+r>>1;
if(R<=mid)
return query_tot(root<<1,l,mid,L,R);
else{
if(L>mid)
return query_tot(root<<1|1,mid+1,r,L,R);
else
return query_tot(root<<1,l,mid,L,mid)+query_tot(root<<1|1,mid+1,r,mid+1,R);
}
}
void query_max(int root,int l,int r,int L,int R){
if(tr[root].l==L&&tr[root].r==R){
ans=max(ans,tr[root].mmid[1]);
ans=max(ans,maxx+tr[root].maxl[1]);
if(tr[root].cnt[1]==tr[root].r-tr[root].l+1)
maxx+=tr[root].cnt[1];
else
maxx=tr[root].maxr[1];
return ;
}
push_down(root);
int mid=l+r>>1;
if(R<=mid)
query_max(root<<1,l,mid,L,R);
else{
if(L>mid)
query_max(root<<1|1,mid+1,r,L,R);
else
query_max(root<<1,l,mid,L,mid),query_max(root<<1|1,mid+1,r,mid+1,R);
}
}
int main(){
n=Read(),q=Read();
for(int i=1;i<=n;++i)
a[i]=Read();
build(1,1,n);
while(q--){
int cz=Read(),l=Read()+1,r=Read()+1;
switch(cz){
case 0:{
update_cov(1,1,n,l,r,0);
break;
}
case 1:{
update_cov(1,1,n,l,r,1);
break;
}
case 2:{
update_rev(1,1,n,l,r);
break;
}
case 3:{
cout<<query_tot(1,1,n,l,r)<<'\n';
break;
}
case 4:{
maxx=ans=0;
query_max(1,1,n,l,r);
cout<<ans<<'\n';
break;
}
}
}
return 0;
}