bzoj1858SCOI 序列操作 (线段树)
题目大意:
给定一个长度为n的01序列为,现在有m种操作
\(0\ a\ b\) 把\([a,b]\)的数全部修改为0
\(1\ a\ b\) 把\([a,b]\)的数全部修改为1
\(2\ a\ b\) 把\([a,b]\)的所有数取反,就是0->1 1->0
\(3\ a\ b\) 询问\([a,b]\)中一共有多少个0
\(4\ a\ b\) 询问\([a,b]\)中最长有多少个连续的1
其中\(n\le100000,m\le 100000\)
一看这个数据范围和题目要求,我们就不难看出这是一个线段树题
首先,我们考虑,因为有取反这个操作的存在,所以我们在维护1的信息的同时,也需要维护0的信息
然后取反的时候,直接\(swap\)就可以了
对于3询问,我们只需要维护一个区间内0的个数和1的个数就可以
而4询问呢,为了方便合并和求答案
所以对于一个节点,我们需要维护这个区间左连续最长的1,右连续最长的1 ,还有整个区间最长的连续的1
以及相对应的0的信息。
合并的时候,如果左区间的连续1的长度覆盖了整个区间,那么大区间的左连续的长度等于左区间的左连续加右区间的左连续的长度
其他的情况同理
void up(int root)
{
    f[root].l=f[2*root].l;
    f[root].r=f[2*root+1].r;
    int l=f[2*root].l,r=f[2*root+1].r;
    int mid =(l+r) >>1;
    f[root].sum0=f[2*root].sum0+f[2*root+1].sum0;
    f[root].sum1=f[2*root].sum1+f[2*root+1].sum1;
    f[root].zuo0=f[2*root].zuo0;
    f[root].zuo1=f[2*root].zuo1;
    if (f[2*root].zuo0==(mid-l+1)) f[root].zuo0+=f[2*root+1].zuo0;
    if (f[2*root].zuo1==(mid-l+1)) f[root].zuo1+=f[2*root+1].zuo1;
    f[root].you0=f[2*root+1].you0;
    f[root].you1=f[2*root+1].you1;
    if (f[2*root+1].you0==(r-mid)) f[root].you0+=f[2*root].you0;
    if (f[2*root+1].you1==(r-mid)) f[root].you1+=f[2*root].you1;
    f[root].ans1=max(f[root*2].ans1,f[2*root+1].ans1);
    f[root].ans1=max(f[root].ans1,f[2*root].you1+f[2*root+1].zuo1);
    f[root].ans0=max(f[root*2].ans0,f[2*root+1].ans0);
    f[root].ans0=max(f[root].ans0,f[2*root].you0+f[2*root+1].zuo0);
}
之后就是pushdown了,我们发现,这个题有两种标记。一种是覆盖,一种是取反
我们考虑 每次覆盖的之后,这个区间原本的取反的标记就没有了,所以覆盖之后要清空覆盖标记
而下传的时候,我们要先覆盖,后取反,不然取反就没有用了
void pushdown(int root,int l,int r)
{
   int mid=(r+l) >> 1;
   if (flag[root]!=-1)
   {
   	  flag[2*root]=flag[root];
   	  flag[2*root+1]=flag[root];
   	  rever[2*root]=0;
   	  rever[2*root+1]=0;
   	  if (flag[root]==1)
   	  {
   	     f[2*root].ans0=f[2*root].sum0=f[2*root].zuo0=f[2*root].you0=0;
         f[2*root].ans1=mid-l+1;f[2*root].sum1=mid-l+1;f[2*root].zuo1=f[2*root].you1=mid-l+1;
         f[2*root+1].ans0=f[2*root+1].sum0=f[2*root+1].zuo0=f[2*root+1].you0=0;
         f[2*root+1].ans1=r-mid;f[2*root+1].sum1=r-mid;f[2*root+1].zuo1=f[2*root+1].you1=r-mid;
      }
      else
      {
      	 f[2*root].ans1=f[2*root].sum1=f[2*root].zuo1=f[2*root].you1=0;
      	 f[2*root].ans0=f[2*root].sum0=f[2*root].zuo0=f[2*root].you0=mid-l+1;
      	 f[2*root+1].ans1=f[2*root+1].sum1=f[2*root+1].zuo1=f[2*root+1].you1=0;
      	 f[2*root+1].ans0=f[2*root+1].sum0=f[2*root+1].zuo0=f[2*root+1].you0=r-mid;
      }
      flag[root]=-1;
   }
   if (rever[root])
   {
   	   rever[2*root]^=1;
   	   rever[2*root+1]^=1;
   	   swap(f[2*root].sum0,f[2*root].sum1);
   	   swap(f[2*root].ans0,f[2*root].ans1);
   	   swap(f[2*root].zuo0,f[2*root].zuo1);
   	   swap(f[2*root].you0,f[2*root].you1);
   	   swap(f[2*root+1].sum0,f[2*root+1].sum1);
   	   swap(f[2*root+1].ans0,f[2*root+1].ans1);
   	   swap(f[2*root+1].zuo0,f[2*root+1].zuo1);
   	   swap(f[2*root+1].you0,f[2*root+1].you1);
   	   rever[root]^=1;
   }
}
其他的update都差不多
再就是query的时候,我们需要返回一个Node类型,然后像up的操作一样进行合并和求答案
直接上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
using namespace std;
inline int read()
{
   int x=0,f=1;char ch=getchar();
   while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
   while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
   return x*f;
}
struct Node{
    int zuo0,you0,zuo1,you1,ans1,ans0,sum0,sum1;
    int l,r;
};
const int maxn = 1e5+1e2;
Node f[maxn*4];
int rever[4*maxn],flag[4*maxn];
int n,m;
int a[maxn];
void up(int root)
{
    f[root].l=f[2*root].l;
    f[root].r=f[2*root+1].r;
    int l=f[2*root].l,r=f[2*root+1].r;
    int mid =(l+r) >>1;
    f[root].sum0=f[2*root].sum0+f[2*root+1].sum0;
    f[root].sum1=f[2*root].sum1+f[2*root+1].sum1;
    f[root].zuo0=f[2*root].zuo0;
    f[root].zuo1=f[2*root].zuo1;
    if (f[2*root].zuo0==(mid-l+1)) f[root].zuo0+=f[2*root+1].zuo0;
    if (f[2*root].zuo1==(mid-l+1)) f[root].zuo1+=f[2*root+1].zuo1;
    f[root].you0=f[2*root+1].you0;
    f[root].you1=f[2*root+1].you1;
    if (f[2*root+1].you0==(r-mid)) f[root].you0+=f[2*root].you0;
    if (f[2*root+1].you1==(r-mid)) f[root].you1+=f[2*root].you1;
    f[root].ans1=max(f[root*2].ans1,f[2*root+1].ans1);
    f[root].ans1=max(f[root].ans1,f[2*root].you1+f[2*root+1].zuo1);
    f[root].ans0=max(f[root*2].ans0,f[2*root+1].ans0);
    f[root].ans0=max(f[root].ans0,f[2*root].you0+f[2*root+1].zuo0);
}
void pushdown(int root,int l,int r)
{
   int mid=(r+l) >> 1;
   if (flag[root]!=-1)
   {
   	  flag[2*root]=flag[root];
   	  flag[2*root+1]=flag[root];
   	  rever[2*root]=0;
   	  rever[2*root+1]=0;
   	  if (flag[root]==1)
   	  {
   	     f[2*root].ans0=f[2*root].sum0=f[2*root].zuo0=f[2*root].you0=0;
         f[2*root].ans1=mid-l+1;f[2*root].sum1=mid-l+1;f[2*root].zuo1=f[2*root].you1=mid-l+1;
         f[2*root+1].ans0=f[2*root+1].sum0=f[2*root+1].zuo0=f[2*root+1].you0=0;
         f[2*root+1].ans1=r-mid;f[2*root+1].sum1=r-mid;f[2*root+1].zuo1=f[2*root+1].you1=r-mid;
      }
      else
      {
      	 f[2*root].ans1=f[2*root].sum1=f[2*root].zuo1=f[2*root].you1=0;
      	 f[2*root].ans0=f[2*root].sum0=f[2*root].zuo0=f[2*root].you0=mid-l+1;
      	 f[2*root+1].ans1=f[2*root+1].sum1=f[2*root+1].zuo1=f[2*root+1].you1=0;
      	 f[2*root+1].ans0=f[2*root+1].sum0=f[2*root+1].zuo0=f[2*root+1].you0=r-mid;
      }
      flag[root]=-1;
   }
   if (rever[root])
   {
   	   rever[2*root]^=1;
   	   rever[2*root+1]^=1;
   	   swap(f[2*root].sum0,f[2*root].sum1);
   	   swap(f[2*root].ans0,f[2*root].ans1);
   	   swap(f[2*root].zuo0,f[2*root].zuo1);
   	   swap(f[2*root].you0,f[2*root].you1);
   	   swap(f[2*root+1].sum0,f[2*root+1].sum1);
   	   swap(f[2*root+1].ans0,f[2*root+1].ans1);
   	   swap(f[2*root+1].zuo0,f[2*root+1].zuo1);
   	   swap(f[2*root+1].you0,f[2*root+1].you1);
   	   rever[root]^=1;
   }
}
void build(int root,int l,int r)
{
    rever[root]=0;
    flag[root]=-1;
    if (l==r)
    {
    	f[root].l=f[root].r=l;
    	if (a[l]==0)
    	{
    		f[root].sum0=f[root].ans0=f[root].zuo0=f[root].you0=1;
        }
        else
        {
            f[root].sum1=f[root].ans1=f[root].zuo1=f[root].you1=1;
        }
        return;
    }
    int mid = (l+r) >> 1;
    build(2*root,l,mid);
    build(2*root+1,mid+1,r);
    up(root);
}
void update0(int root,int l,int r,int x,int y)
{
    if (x<=l && r<=y)
    {
        flag[root]=0;
        f[root].ans1=f[root].sum1=f[root].zuo1=f[root].you1=0;
      	f[root].ans0=f[root].sum0=f[root].zuo0=f[root].you0=r-l+1;
      	rever[root]=0;
      	return;
    }
    pushdown(root,l,r);
    int mid =(l+r) >> 1;
    if (x<=mid) update0(2*root,l,mid,x,y);
    if (y>mid) update0(2*root+1,mid+1,r,x,y);
    up(root);
}
void update1(int root,int l,int r,int x,int y)
{
    if (x<=l && r<=y)
    {
        flag[root]=1;
        rever[root]=0;
        f[root].ans0=f[root].sum0=f[root].zuo0=f[root].you0=0;
      	f[root].ans1=f[root].sum1=f[root].zuo1=f[root].you1=r-l+1;
      	return;
    }
    pushdown(root,l,r);
    int mid = (l+r) >> 1;
    if (x<=mid) update1(2*root,l,mid,x,y);
    if (y>mid) update1(2*root+1,mid+1,r,x,y);
    up(root);
}
void reverse(int root,int l,int r,int x,int y)
{
    if (x<=l && r<=y)
    {
        rever[root]^=1;
        swap(f[root].sum0,f[root].sum1);
   	    swap(f[root].ans0,f[root].ans1);
   	    swap(f[root].zuo0,f[root].zuo1);
   	    swap(f[root].you0,f[root].you1);
   	    return;
    }
    pushdown(root,l,r);
    int mid = (l+r) >> 1;
    if (x<=mid) reverse(2*root,l,mid,x,y);
    if (y>mid) reverse(2*root+1,mid+1,r,x,y);
    up(root);
}
int querysum(int root,int l,int r,int x,int y)
{
    if (x<=l && r<=y)
    {
        return f[root].sum1;
    }
    pushdown(root,l,r);
    int mid = (l+r) >> 1;
    int ans=0;
    if (x<=mid) ans+=querysum(2*root,l,mid,x,y);
    if (y>mid) ans+=querysum(2*root+1,mid+1,r,x,y);
    return ans;
}
Node queryans(int root,int l,int r,int x,int y)
{
    if (x<=l && r<=y)
    {
        return f[root];
    }
    pushdown(root,l,r);
    int mid = (l+r) >> 1;
    Node ans,ans1,ans2;
    ans=ans1=ans2=f[4*maxn-10];
    if (x<=mid) {
        ans1=queryans(2*root,l,mid,x,y);
    }
    if (y>mid){
        ans2=queryans(2*root+1,mid+1,r,x,y);
    }
    //cout<<"gg"<<endl;
    ans.sum0=ans1.sum0+ans2.sum0;
    ans.sum1=ans1.sum1+ans2.sum1;
    ans.zuo0=ans1.zuo0;
    ans.zuo1=ans1.zuo1;
    if (ans1.zuo0==(mid-l+1)) ans.zuo0+=ans2.zuo0;
    if (ans1.zuo1==(mid-l+1)) ans.zuo1+=ans2.zuo1;
    ans.you0=ans2.you0;
    ans.you1=ans2.you1;
    if (ans2.you0==(r-mid)) ans.you0+=ans1.you0;
    if (ans2.you1==(r-mid)) ans.you1+=ans1.you1;
    ans.ans1=max(ans1.ans1,ans2.ans1);
    ans.ans1=max(ans.ans1,ans1.you1+ans2.zuo1);
    ans.ans0=max(ans1.ans0,ans2.ans0);
    ans.ans0=max(ans.ans0,ans1.you0+ans2.zuo0);
    return ans;
}
int main()
{
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++) a[i]=read();
  build(1,1,n);
  //cout<<f[1].ans1<<endl;
  for (int i=1;i<=m;i++)
  {
  	 int opt=read();
  	 int x=read(),y=read();
  	 x++;
  	 y++;
  	 if (opt==0){
  	 	update0(1,1,n,x,y);
       }
    if (opt==1)
    {
        update1(1,1,n,x,y);
    }
    if (opt==2)
    {
        reverse(1,1,n,x,y);
    }
    if (opt==3)
    {
        printf("%d\n",querysum(1,1,n,x,y));
    }
    if (opt==4)
    {
        Node ans=queryans(1,1,n,x,y);
        printf("%d\n",ans.ans1);
    }
    //cout<<querysum(1,1,n,1,6)<<"gg"<<endl;
    //cout<<yy.ans1<<endl;
  }
  return 0;
}
bzoj1858SCOI 序列操作 (线段树)的更多相关文章
- 【题解】P4247 [清华集训]序列操作(线段树修改DP)
		[题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ... 
- 【BZOJ-2962】序列操作       线段树 + 区间卷积
		2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 678 Solved: 246[Submit][Status][Discuss] ... 
- 【BZOJ-1858】序列操作     线段树
		1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1961 Solved: 991[Submit][Status ... 
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
		略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ... 
- 【bzoj1858】[Scoi2010]序列操作  线段树区间合并
		题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ... 
- 【BZOJ2962】序列操作 线段树
		[BZOJ2962]序列操作 Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反 ... 
- Luogu P2572 [SCOI2010]序列操作 线段树。。
		咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ... 
- 洛谷$P2572\ [SCOI2010]$ 序列操作 线段树/珂朵莉树
		正解:线段树/珂朵莉树 解题报告: 传送门$w$ 本来是想写线段树的,,,然后神仙$tt$跟我港可以用珂朵莉所以决定顺便学下珂朵莉趴$QwQ$ 还是先写线段树做法$QwQ$? 操作一二三四都很$eas ... 
- bzoj1858[Scoi2010]序列操作 线段树
		1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 3079 Solved: 1475[Submit][Statu ... 
- [SCOI2010]序列操作 线段树
		---题面--- 题解: 在考场上打的这道题,出人意料的很快就打完了?! 直接用线段树,维护几个东西: 1,lazy标记 : 表示区间赋值 2,mark标记:表示区间翻转 3,l1:前缀最长连续的1的 ... 
随机推荐
- Linux centos7 nginx 的安装
			2021-08-18 1. 环境 # 操作系统[root@test007 /]# uname -aLinux test007 3.10.0-862.el7.x86_64 #1 SMP Fri Apr ... 
- 剑指 Offer 34. 二叉树中和为某一值的路径
			剑指 Offer 34. 二叉树中和为某一值的路径 输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径.从树的根节点开始往下一直到叶节点所经过的节点形成一条路径. 示例: 给定如下 ... 
- 如何实现 Android 短视频跨页面的流畅续播?
			在一切皆可视频化的今天,短视频内容作为移动端产品新的促活点,受到了越来越多的重视与投入,同时短视频也是增加用户粘性.增加用户停留时长的一把利器.那么如何快速实现移动端短视频功能呢?前两篇我们介绍了盒马 ... 
- Mybatis(三)——全局配置文件
			二.properties 三.settings 四.typeAilases 这里不做介绍. 
- shell循环之跳出循环
			1.break break命令允许跳出所有循环(终止执行后面的所有循环). 下面的例子中,脚本进入死循环直至用户输入数字大于5.要跳出这个循环,返回到shell提示符下,需要使用break命令. #! ... 
- Android系统编程入门系列之应用内数据保存数据库
			上篇文章已经介绍了如何使用SharedPreferences存储键值对形式的轻量级数据,对于那些相同结构的多组数据,类似于存储Java中定义的类的多个对象属性值,如果按照键值对的形式一条条读写,需要分 ... 
- Python常见问题 - python3 requests库提示警告InsecureRequestWarning的问题
			当使用 requests 库发送请求时报了以下警告 D:\python3.6\lib\site-packages\urllib3\connectionpool.py:847: InsecureRequ ... 
- python3 用multiprocessing模块传递多个参数
			from datetime import datetime from time import sleep import numpy as np import multiprocessing # fro ... 
- docker-compose up -d nginx 报错
			在阿里云ECS上创建nginx容器时,报错如上图. The solution: In your Dockerfile, before running any apt commands, add the ... 
- C# Dapper基本三层架构使用 (三、BLL)
			BLL层介绍 业务逻辑层用于做一些有效性验证的工作,以更好的保证程序运行的健壮性.如完成数据添加.修改和查询业务等:不允许指定的文本框中输入空字符串,数据格式是否正确以及数据类型验证:用户权限的合法性 ... 
