[SCOI2010] 序列操作
码量稍微有点大但思维难度比较低。有些细节需要注意。
首先由于序列中的元素只可能是0或1,所以可以暴力维护0和1的数量,反转的时候交换即可。至于最长连续1子段的长度则可以用维护最大子段和的方法维护,分别维护左最长、右最长以及全局最长。考虑到反转之后可能需要重新统计,对于每一个节点同时维护0的三个最长,反转的时候直接交换对应值即可。
最大的问题(至少是卡了我半个小时的问题)是pushnow操作。覆盖还好说,主要是反转的时候要注意当前已有的lazy,不能简单地把lazy赋值为3,因为前面的操作可能还没有下放到孩子那里,直接赋值会导致操作的丢失。正确方法是分类讨论,假如当前的lazy是1或2,那么说明所有元素是一样的,反转操作就相当于是一次区间推平操作。至于0或3的情况,3时应该赋值为0,因为反转两次就相当于没有反转。就这么个东西我研究了半天才发现错误。我太弱了。
code:
#include<bits/stdc++.h>
//#define feyn
const int N=100010;
using namespace std;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
inline int max(int s1,int s2){
return s1<s2?s2:s1;
}
inline void swap(int &s1,int &s2){
int s3=s1;s1=s2;s2=s3;return;
}
#define lc (wh<<1)
#define rc (wh<<1|1)
#define mid (t[wh].l+t[wh].r>>1)
#define num (t[wh].r-t[wh].l+1)
struct node{
int l,r;
int l0,r0,a0;
int l1,r1,a1;
int sum0,sum1;
int lazy;//1:all_0 2:all_1 3:swaping
bool all0,all1;
}t[N<<2];
inline void pushup(int wh){
t[wh].all0=t[lc].all0&&t[rc].all0;
t[wh].all1=t[lc].all1&&t[rc].all1;
t[wh].sum0=t[lc].sum0+t[rc].sum0;
t[wh].sum1=t[lc].sum1+t[rc].sum1;
t[wh].l0=t[lc].all0?t[lc].l0+t[rc].l0:t[lc].l0;
t[wh].r0=t[rc].all0?t[rc].r0+t[lc].r0:t[rc].r0;
t[wh].a0=max(max(t[lc].a0,t[rc].a0),t[lc].r0+t[rc].l0);
t[wh].l1=t[lc].all1?t[lc].l1+t[rc].l1:t[lc].l1;
t[wh].r1=t[rc].all1?t[rc].r1+t[lc].r1:t[rc].r1;
t[wh].a1=max(max(t[lc].a1,t[rc].a1),t[lc].r1+t[rc].l1);
}
inline void pushnow(int wh,int val){
if(val==1){
t[wh].lazy=val;
t[wh].l0=t[wh].r0=t[wh].a0=t[wh].sum0=num;
t[wh].l1=t[wh].r1=t[wh].a1=t[wh].sum1=0;
t[wh].all0=true,t[wh].all1=false;
}
if(val==2){
t[wh].lazy=val;
t[wh].l0=t[wh].r0=t[wh].a0=t[wh].sum0=0;
t[wh].l1=t[wh].r1=t[wh].a1=t[wh].sum1=num;
t[wh].all0=false,t[wh].all1=true;
}
if(val==3){
if(t[wh].lazy==1||t[wh].lazy==2){
t[wh].lazy=3-t[wh].lazy;
}
else if(t[wh].lazy==3)t[wh].lazy=0;
else t[wh].lazy=3;
swap(t[wh].l0,t[wh].l1);
swap(t[wh].r0,t[wh].r1);
swap(t[wh].a0,t[wh].a1);
swap(t[wh].sum0,t[wh].sum1);
if(t[wh].all0)t[wh].all1=true,t[wh].all0=false;
else if(t[wh].all1)t[wh].all1=false,t[wh].all0=true;
}
}
inline void pushdown(int wh){
if(t[wh].lazy){
pushnow(lc,t[wh].lazy);
pushnow(rc,t[wh].lazy);
t[wh].lazy=0;
}
}
inline void build(int wh,int l,int r,int a[]){
t[wh].l=l;t[wh].r=r;t[wh].lazy=0;
if(l==r){
pushnow(wh,a[l]==0?1:2);return;
}
build(lc,l,mid,a);
build(rc,mid+1,r,a);
pushup(wh);
}
inline void change(int wh,int wl,int wr,int val){
if(wl<=t[wh].l&&t[wh].r<=wr){
pushnow(wh,val);
return;
}
pushdown(wh);
if(wl<=mid)change(lc,wl,wr,val);
if(wr>mid)change(rc,wl,wr,val);
pushup(wh);
}
inline int worknum(int wh,int wl,int wr){
if(wl<=t[wh].l&&t[wh].r<=wr){
return t[wh].sum1;
}
int an=0;
pushdown(wh);
if(wl<=mid)an+=worknum(lc,wl,wr);
if(wr>mid)an+=worknum(rc,wl,wr);
pushup(wh);return an;
}
struct aa{int l,r,data;bool all;};
inline aa operator +(aa a,aa b){
return (aa){a.all?a.l+b.l:a.l,b.all?b.r+a.r:b.r,max(max(a.data,b.data),a.r+b.l),a.all&&b.all};
}
inline aa worklen(int wh,int wl,int wr){
if(wl<=t[wh].l&&t[wh].r<=wr){
return (aa){t[wh].l1,t[wh].r1,t[wh].a1,t[wh].all1};
}
pushdown(wh);
if(wl<=mid&&wr>mid)return worklen(lc,wl,wr)+worklen(rc,wl,wr);
else if(wl<=mid)return worklen(lc,wl,wr);
else return worklen(rc,wl,wr);
}
#undef lc
#undef rc
#undef mid
#undef num
int m,n,ss[N];
signed main(){
#ifdef feyn
freopen("in.txt","r",stdin);
#endif
read(m);read(n);
for(int i=1;i<=m;i++)read(ss[i]);
build(1,1,m,ss);
int op,l,r;
for(int ii=1;ii<=n;ii++){read(op);read(l);read(r);
l++,r++;
if(op<3){
change(1,l,r,op+1);
continue;
}
if(op==3)printf("%d\n",worknum(1,l,r));
else printf("%d\n",worklen(1,l,r).data);
}
return 0;
}
一如既往,万事胜意