• 【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
    ",querysum1(1,a,b));
    		break;
    	  }
    	  case 4:
    	  {
    	    mx=rmx=0;
    		querylen1(1,a,b);
    	    printf("%d
    ",mx);
    		break;
    	  }
    	}
      }
      
      return 0;
    }
    


  • 相关阅读:
    MongoDB的安装和常用命令
    mysql安装、使用与遇见的问题汇总
    devicePixelRatio,Viewport,移动端适配
    javascript 数组以及对象的深拷贝(复制数组或复制对象)的方法
    正则表达式
    npm 常用命令
    Markdown 基本语法
    mysql忘记root密码
    mysql5.7.12/13在安装新实例时报错:InnoDB: auto-extending data file ./ibdata1 is of a different size 640 pages (rounded down to MB) than specified in the .cnf file: initial 768 pages, max 0 (relevant if non-zero
    mysqld数据位于a盘,执行delete from table, 发现另外2个盘磁盘使用率接近100%,而a盘的使用率反而很低,y??
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793716.html
Copyright © 2020-2023  润新知