【BZOJ1858】序列操作(SCOI2010)-线段树
测试地址:序列操作
做法:这个题是很久以前做的,大概去年8月份吧,但是忘记放博客上了,今天突然想起来补档。这个题虽然很容易看出是用线段树维护,但是要维护的信息太多了......简单整理一下就是:区间内0和1的数量,左端和右端连续0和连续1的长度,区间内最长的连续0和连续1的长度,覆盖标记,取反标记。其中最恶心的就是两个标记的处理顺序,可以发现这两个标记是相互影响的,需要好好思考如何处理,具体的处理还是看我巨丑无比的代码吧......
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,a[100010],mx,rmx;
struct node
{
int l,r,sum0,sum1;
int len0,llen0,rlen0,len1,llen1,rlen1;
int cov,flag;
}seg[400010];
void pushdown(int no)
{
int mid=(seg[no].l+seg[no].r)>>1;
if (seg[no].flag==-1)
{
if (seg[no<<1].cov==-1) seg[no<<1].flag=-seg[no<<1].flag;
else seg[no<<1].cov=!seg[no<<1].cov;
if (seg[(no<<1)+1].cov==-1) seg[(no<<1)+1].flag=-seg[(no<<1)+1].flag;
else seg[(no<<1)+1].cov=!seg[(no<<1)+1].cov;
swap(seg[no<<1].sum0,seg[no<<1].sum1);
swap(seg[no<<1].len0,seg[no<<1].len1);
swap(seg[no<<1].llen0,seg[no<<1].llen1);
swap(seg[no<<1].rlen0,seg[no<<1].rlen1);
swap(seg[(no<<1)+1].sum0,seg[(no<<1)+1].sum1);
swap(seg[(no<<1)+1].len0,seg[(no<<1)+1].len1);
swap(seg[(no<<1)+1].llen0,seg[(no<<1)+1].llen1);
swap(seg[(no<<1)+1].rlen0,seg[(no<<1)+1].rlen1);
seg[no].flag=1;
}
if (seg[no].cov!=-1)
{
seg[no<<1].cov=seg[(no<<1)+1].cov=seg[no].cov;
if (seg[no].cov==0)
{
seg[no<<1].sum0=seg[no<<1].len0=seg[no<<1].llen0=seg[no<<1].rlen0=mid-seg[no].l+1;
seg[(no<<1)+1].sum0=seg[(no<<1)+1].len0=seg[(no<<1)+1].llen0=seg[(no<<1)+1].rlen0=seg[no].r-mid;
seg[no<<1].sum1=seg[no<<1].len1=seg[no<<1].llen1=seg[no<<1].rlen1=0;
seg[(no<<1)+1].sum1=seg[(no<<1)+1].len1=seg[(no<<1)+1].llen1=seg[(no<<1)+1].rlen1=0;
}
else
{
seg[no<<1].sum0=seg[no<<1].len0=seg[no<<1].llen0=seg[no<<1].rlen0=0;
seg[(no<<1)+1].sum0=seg[(no<<1)+1].len0=seg[(no<<1)+1].llen0=seg[(no<<1)+1].rlen0=0;
seg[no<<1].sum1=seg[no<<1].len1=seg[no<<1].llen1=seg[no<<1].rlen1=mid-seg[no].l+1;
seg[(no<<1)+1].sum1=seg[(no<<1)+1].len1=seg[(no<<1)+1].llen1=seg[(no<<1)+1].rlen1=seg[no].r-mid;
}
seg[no].cov=-1;
}
}
void pushup(int no)
{
int mid=(seg[no].l+seg[no].r)>>1;
seg[no].sum0=seg[no<<1].sum0+seg[(no<<1)+1].sum0;
seg[no].sum1=seg[no<<1].sum1+seg[(no<<1)+1].sum1;
seg[no].len0=max(seg[no<<1].rlen0+seg[(no<<1)+1].llen0,max(seg[no<<1].len0,seg[(no<<1)+1].len0));
seg[no].len1=max(seg[no<<1].rlen1+seg[(no<<1)+1].llen1,max(seg[no<<1].len1,seg[(no<<1)+1].len1));
seg[no].llen0=seg[no<<1].llen0;if (seg[no<<1].llen0==mid-seg[no].l+1) seg[no].llen0+=seg[(no<<1)+1].llen0;
seg[no].llen1=seg[no<<1].llen1;if (seg[no<<1].llen1==mid-seg[no].l+1) seg[no].llen1+=seg[(no<<1)+1].llen1;
seg[no].rlen0=seg[(no<<1)+1].rlen0;if (seg[(no<<1)+1].rlen0==seg[no].r-mid) seg[no].rlen0+=seg[no<<1].rlen0;
seg[no].rlen1=seg[(no<<1)+1].rlen1;if (seg[(no<<1)+1].rlen1==seg[no].r-mid) seg[no].rlen1+=seg[no<<1].rlen1;
}
void buildtree(int no,int l,int r)
{
int mid=(l+r)>>1;
seg[no].l=l;seg[no].r=r;seg[no].cov=-1;seg[no].flag=1;
if (l==r)
{
if (a[l]==0)
{
seg[no].sum0=1,seg[no].sum1=0;
seg[no].len0=seg[no].llen0=seg[no].rlen0=1;
seg[no].len1=seg[no].llen1=seg[no].rlen1=0;
}
if (a[l]==1)
{
seg[no].sum0=0,seg[no].sum1=1;
seg[no].len0=seg[no].llen0=seg[no].rlen0=0;
seg[no].len1=seg[no].llen1=seg[no].rlen1=1;
}
return;
}
buildtree(no<<1,l,mid);
buildtree((no<<1)+1,mid+1,r);
pushup(no);
}
void cover(int no,int s,int t,int f)
{
int mid=(seg[no].l+seg[no].r)>>1;
if (seg[no].l>=s&&seg[no].r<=t)
{
seg[no].flag=1;seg[no].cov=f;
if (f==0)
{
seg[no].sum0=seg[no].len0=seg[no].llen0=seg[no].rlen0=seg[no].r-seg[no].l+1;
seg[no].sum1=seg[no].len1=seg[no].llen1=seg[no].rlen1=0;
}
else
{
seg[no].sum0=seg[no].len0=seg[no].llen0=seg[no].rlen0=0;
seg[no].sum1=seg[no].len1=seg[no].llen1=seg[no].rlen1=seg[no].r-seg[no].l+1;
}
return;
}
pushdown(no);
if (s<=mid) cover(no<<1,s,t,f);
if (t>mid) cover((no<<1)+1,s,t,f);
pushup(no);
}
void negate_(int no,int s,int t)
{
int mid=(seg[no].l+seg[no].r)>>1;
if (seg[no].l>=s&&seg[no].r<=t)
{
if (seg[no].cov==-1) seg[no].flag=-seg[no].flag;
else seg[no].cov=!seg[no].cov;
swap(seg[no].sum0,seg[no].sum1);
swap(seg[no].len0,seg[no].len1);
swap(seg[no].llen0,seg[no].llen1);
swap(seg[no].rlen0,seg[no].rlen1);
return;
}
pushdown(no);
if (s<=mid) negate_(no<<1,s,t);
if (t>mid) negate_((no<<1)+1,s,t);
pushup(no);
}
int querysum1(int no,int s,int t)
{
int mid=(seg[no].l+seg[no].r)>>1;
if (seg[no].l>=s&&seg[no].r<=t) return seg[no].sum1;
pushdown(no);
int sum=0;
if (s<=mid) sum+=querysum1(no<<1,s,t);
if (t>mid) sum+=querysum1((no<<1)+1,s,t);
pushup(no);
return sum;
}
void querylen1(int no,int s,int t)
{
int mid=(seg[no].l+seg[no].r)>>1;
if (seg[no].l>=s&&seg[no].r<=t)
{
mx=max(mx,max(rmx+seg[no].llen1,seg[no].len1));
if (seg[no].rlen1==seg[no].r-seg[no].l+1) rmx+=seg[no].rlen1;
else rmx=seg[no].rlen1;
return;
}
pushdown(no);
if (s<=mid) querylen1(no<<1,s,t);
if (t>mid) querylen1((no<<1)+1,s,t);
pushup(no);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
buildtree(1,0,n-1);
for(int i=1;i<=m;i++)
{
int op,a,b;
scanf("%d%d%d",&op,&a,&b);
switch(op)
{
case 0:
{
cover(1,a,b,0);
break;
}
case 1:
{
cover(1,a,b,1);
break;
}
case 2:
{
negate_(1,a,b);
break;
}
case 3:
{
printf("%d\n",querysum1(1,a,b));
break;
}
case 4:
{
mx=rmx=0;
querylen1(1,a,b);
printf("%d\n",mx);
break;
}
}
}
return 0;
}