【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;
}


posted @ 2017-04-25 16:58  Maxwei_wzj  阅读(106)  评论(0编辑  收藏  举报