题目大意:

给定一个长度为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 序列操作 (线段树)的更多相关文章

  1. 【题解】P4247 [清华集训]序列操作(线段树修改DP)

    [题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...

  2. 【BZOJ-2962】序列操作 线段树 + 区间卷积

    2962: 序列操作 Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 678  Solved: 246[Submit][Status][Discuss] ...

  3. 【BZOJ-1858】序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1961  Solved: 991[Submit][Status ...

  4. BZOJ 1858: [Scoi2010]序列操作( 线段树 )

    略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...

  5. 【bzoj1858】[Scoi2010]序列操作 线段树区间合并

    题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...

  6. 【BZOJ2962】序列操作 线段树

    [BZOJ2962]序列操作 Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反 ...

  7. Luogu P2572 [SCOI2010]序列操作 线段树。。

    咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...

  8. 洛谷$P2572\ [SCOI2010]$ 序列操作 线段树/珂朵莉树

    正解:线段树/珂朵莉树 解题报告: 传送门$w$ 本来是想写线段树的,,,然后神仙$tt$跟我港可以用珂朵莉所以决定顺便学下珂朵莉趴$QwQ$ 还是先写线段树做法$QwQ$? 操作一二三四都很$eas ...

  9. bzoj1858[Scoi2010]序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 3079  Solved: 1475[Submit][Statu ...

  10. [SCOI2010]序列操作 线段树

    ---题面--- 题解: 在考场上打的这道题,出人意料的很快就打完了?! 直接用线段树,维护几个东西: 1,lazy标记 : 表示区间赋值 2,mark标记:表示区间翻转 3,l1:前缀最长连续的1的 ...

随机推荐

  1. 用C++实现的Euler筛法程序

    Euler筛法介绍 以筛出100以内(含100)的所有素数为例来说明一下欧拉筛法的原理. 和Eratosthenes筛法一样,Euler筛法也从2开始筛,但Eratosthenes筛法会把2的倍数一批 ...

  2. JavaWeb中表单数据的获取及乱码问题

    首先使用一个用户提交界面作为举例(文本框,密码框,选择,下拉表单等),效果如下 注:HTML < form> 标签的 action 属性,其定义和用法是: 属性值为URL,表示向何处发送表 ...

  3. JavaScript高级程序设计(读书笔记)之函数表达式

    定义函数的方式有两种:一种是函数声明,另一种就是函数表达式. 函数声明的一个重要特征就是函数声明提升(function declaration hoisting),意思是在执行代码前会先读取函数声明. ...

  4. Kafka详细教程加面试题

    一.部署kafka集群 启动zookeeper服务: zkServer.sh start 修改配置文件config/server.properties #broker 的全局唯一编号,不能重复 bro ...

  5. 华为分析X HUAWEI Ads,上线深度转化事件回传功能,让ROI 看得见!

    华为分析X HUAWEI Ads,上线深度转化事件回传功能,让ROI 看得见! 随着移动应用生态的流量成本攀升.行业竞争加剧,越来越多的广告商希望通过精准投放来获取更高质量的深度转化用户,比如二手车. ...

  6. Python之requests模块-cookie

    cookie并不陌生,与session一样,能够让http请求前后保持状态.与session不同之处,在于cookie数据仅保存于客户端.requests也提供了相应到方法去处理cookie. 在py ...

  7. Redis消息的发布与订阅

  8. Flask(4)- URL 组成部分详解

    URL Uniform Resource Locator 的简写,中文名叫统一资源定位符 用于表示服务端的各种资源,例如网页 下面将讲解 Flask 中如何提取组成 URL 的各个部分   URL 组 ...

  9. 10分钟学会VS NuGet包私有化部署

    前言 我们之前实现了打包发布NuGet,但是发布后的引用是公有的,谁都可以访问,显然这种方式是不可取的. 命令版本:10分钟学会Visual Studio将自己创建的类库打包到NuGet进行引用(ne ...

  10. 事务保存点savepoint

    一.