[SCOI2010] 序列操作

link

码量稍微有点大但思维难度比较低。有些细节需要注意。

首先由于序列中的元素只可能是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;
}
posted @ 2022-07-07 17:12  Feyn618  阅读(41)  评论(0编辑  收藏  举报