BZOJ_1858_[Scoi2010]序列操作_线段树
BZOJ_1858_[Scoi2010]序列操作_线段树
Description
lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 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]区间内总共有多少个1 4 a b 询问[a, b]区间内最多有多少个连续的1 对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?
Input
输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目 第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op, a, b,(0 < = op < = 4,0 < = a < = b)
Output
对于每一个询问操作,输出一行,包括1个数,表示其对应的答案
Sample Input
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
Sample Output
2
6
5
HINT
对于30%的数据,1<=n, m<=1000 对于100%的数据,1< = n, m < = 100000
分析:线段树处理多个标记。
我这里是先下传取反标记,后下传覆盖标记。
这样的话。如果操作是先覆盖后取反,就在取反的函数中判断一下,如果有覆盖就把覆盖的值取反。
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100050
#define ls p<<1
#define rs p<<1|1
int t[N<<2],cov[N<<2],rev[N<<2],n,m;
int lx[N<<2][2],rx[N<<2][2],nx[N<<2][2],siz[N<<2];
void pushup(int p) {
t[p]=t[ls]+t[rs];
for(int i=0;i<2;i++) {
if(nx[ls][i]==siz[ls]) lx[p][i]=siz[ls]+lx[rs][i];
else lx[p][i]=lx[ls][i];
if(nx[rs][i]==siz[rs]) rx[p][i]=siz[rs]+rx[ls][i];
else rx[p][i]=rx[rs][i];
nx[p][i]=max(max(rx[ls][i]+lx[rs][i],nx[ls][i]),nx[rs][i]);
}
}
void build(int l,int r,int p) {
cov[p]=-1;
siz[p]=r-l+1;
if(l==r) {
scanf("%d",&t[p]);
lx[p][1]=rx[p][1]=nx[p][1]=t[p];
lx[p][0]=rx[p][0]=nx[p][0]=!t[p];
return ;
}
int mid=l+r>>1;
build(l,mid,ls);
build(mid+1,r,rs);
pushup(p);
}
void pushdown(int p) {
if(rev[p]) {
t[ls]=siz[ls]-t[ls];
swap(lx[ls][0],lx[ls][1]);
swap(rx[ls][0],rx[ls][1]);
swap(nx[ls][0],nx[ls][1]);
if(cov[ls]!=-1)cov[ls]^=1;
rev[ls]^=1;
t[rs]=siz[rs]-t[rs];
swap(lx[rs][0],lx[rs][1]);
swap(rx[rs][0],rx[rs][1]);
swap(nx[rs][0],nx[rs][1]);
if(cov[rs]!=-1)cov[rs]^=1;
rev[rs]^=1;
rev[p]=0;
}
if(cov[p]!=-1) {
int d=cov[p];
cov[ls]=cov[rs]=d;
lx[ls][d]=rx[ls][d]=nx[ls][d]=siz[ls];
lx[rs][d]=rx[rs][d]=nx[rs][d]=siz[rs];
lx[ls][!d]=rx[ls][!d]=nx[ls][!d]=lx[rs][!d]=rx[rs][!d]=nx[rs][!d]=0;
t[ls]=siz[ls]*d;
t[rs]=siz[rs]*d;
cov[p]=-1;
}
}
void uprever(int l,int r,int x,int y,int p) {
if(x<=l&&y>=r) {
t[p]=siz[p]-t[p];
swap(lx[p][0],lx[p][1]);
swap(rx[p][0],rx[p][1]);
swap(nx[p][0],nx[p][1]);
rev[p]^=1;
if(cov[p]!=-1) cov[p]^=1;
return ;
}
pushdown(p);
int mid=l+r>>1;
if(x<=mid) uprever(l,mid,x,y,ls);
if(y>mid) uprever(mid+1,r,x,y,rs);
pushup(p);
}
void update(int l,int r,int x,int y,int c,int p) {
if(x<=l&&y>=r) {
cov[p]=c;
lx[p][c]=rx[p][c]=nx[p][c]=siz[p];
lx[p][!c]=rx[p][!c]=nx[p][!c]=0;
t[p]=siz[p]*c;
return ;
}
pushdown(p);
int mid=l+r>>1;
if(x<=mid) update(l,mid,x,y,c,ls);
if(y>mid) update(mid+1,r,x,y,c,rs);
pushup(p);
}
int qsum(int l,int r,int x,int y,int p) {
if(x<=l&&y>=r) return t[p];
pushdown(p);
int re=0,mid=l+r>>1;
if(x<=mid) re+=qsum(l,mid,x,y,ls);
if(y>mid) re+=qsum(mid+1,r,x,y,rs);
return re;
}
int qcon(int l,int r,int x,int y,int p) {
if(x<=l&&y>=r) return nx[p][1];
pushdown(p);
int ansl,ansr,ansm,mid=l+r>>1;
if(y<=mid) return qcon(l,mid,x,y,ls);
else if(x>mid) return qcon(mid+1,r,x,y,rs);
else {
ansl=qcon(l,mid,x,y,ls);
ansr=qcon(mid+1,r,x,y,rs);
ansm=min(mid-x+1,rx[ls][1])+min(y-mid,lx[rs][1]);
return max(max(ansl,ansr),ansm);
}
}
int main() {
scanf("%d%d",&n,&m);
int i,opt,x,y;
build(1,n,1);
for(i=1;i<=m;i++) {
scanf("%d%d%d",&opt,&x,&y);
x++;y++;
if(opt==0) {
update(1,n,x,y,0,1);
}else if(opt==1) {
update(1,n,x,y,1,1);
}else if(opt==2) {
uprever(1,n,x,y,1);
}else if(opt==3) {
printf("%d\n",qsum(1,n,x,y,1));
}else {
printf("%d\n",qcon(1,n,x,y,1));
}
}
}
BZOJ_1858_[Scoi2010]序列操作_线段树的更多相关文章
- BZOJ1858 [Scoi2010]序列操作(线段树)
题目链接 [Scoi2010]序列操作 考验代码能力的一道好题. 思想还是很简单的(直接上线段树),但是比较难写. #include <bits/stdc++.h> using names ...
- [SCOI2010]序列操作 BZOJ1858 线段树
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...
- [bzoj2962]序列操作_线段树_区间卷积
序列操作 bzoj-2962 题目大意:给定一个n个数的正整数序列,m次操作.支持:1.区间加:2.区间取相反数:3.区间求选c个数的乘积和. 注释:$1\le n,m\le 5\cdot 10^4$ ...
- BZOJ_2962_序列操作_线段树
Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问 ...
- bzoj 1858: [Scoi2010]序列操作【线段树】
合并中间那块的时候没取max--WAWAWA 在线段树上维护一堆东西,分别是len区间长度,sm区间内1的个数,ll0区间从左开始最长连续0,ml0区间中间最长连续0,rl0区间从右开始最长连续0,l ...
- 【BZOJ1858】序列操作(线段树)
[BZOJ1858]序列操作(线段树) 题面 BZOJ 题解 这题思路很简单,细节很烦,很码 维护区间翻转和区间赋值标记 当打到区间赋值标记时直接覆盖掉翻转标记 下放标记的时候先放赋值标记再放翻转标记 ...
- 【BZOJ2962】序列操作(线段树)
[BZOJ2962]序列操作(线段树) 题面 BZOJ 题解 设\(s[i]\)表示区间内选择\(i\)个数的乘积的和 考虑如何向上合并? \(s[k]=\sum_{i=0}^klson.s[i]*r ...
- bzoj1858SCOI 序列操作 (线段树)
题目大意: 给定一个长度为n的01序列为,现在有m种操作 \(0\ a\ b\) 把\([a,b]\)的数全部修改为0 \(1\ a\ b\) 把\([a,b]\)的数全部修改为1 \(2\ a\ b ...
- 序列操作 BZOJ2962 线段树
分析: 数据范围表示:c特别的小(c<20) 我们可以考虑nlogn*c^2的算法. 线段树维护区间信息:f[i]表示在[l,r]这段区间中选择i个数相乘的和. 因此,我们可以将区间看成一个点, ...
随机推荐
- Tomcat的缺省是多少,怎么修改
Tomcat的缺省端口号是8080. 修改Tomcat端口号: 1.找到Tomcat目录下的conf文件夹 2.进入conf文件夹里面找到server.xml文件 3.打开server.xml文件 ...
- JVM组成
java内存组成介绍:堆(Heap)和非堆(Non-heap)内存 按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配.堆是在 Java 虚拟机启动时 ...
- Ocelot中文文档-GraphQL
好吧!你明白我的意思Ocelot并不直接支持GraphQL,但有这么多人问起它,我想表明整合graphql-dotnet库是多么容易 请参阅示例项目OcelotGraphQL. 结合使用graphql ...
- cocos2d-x 欢乐捕鱼游戏总结
这几天一直都在做一个捕鱼游戏Demo,大概花掉了我快一个礼拜的时间.游戏主体是使用的cocos2d-x高级开发教程里面提供的小部分框架基本功能.然后自己加入所有的UI元素和玩法.变成了一个体验不错的捕 ...
- 让程序跳转到绝对地址0x100000去执行
网上比较火的一个题,让程序跳转到绝对地址去执行 :可以的实现方式为: ( (void(*)())0x4110e6)(); (*(void(*)())0x4110e6)(); (*((void(*)() ...
- Django rest framework源码分析(3)----节流
目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...
- Python进阶开发之元类编程
系列文章 √第一章 元类编程,已完成 ; 本文目录 类是如何产生的如何使用type创建类理解什么是元类使用元类的意义元类实战:ORM . 类是如何产生的 类是如何产生?这个问题肯定很傻.实则不然,很多 ...
- 报错:严重: Servlet.service() for servlet [springmvc] in context with path [ ] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
解决:service类或dao类需要@Autowired
- [已解决]pycharm的debugger模式不显示调试结果?
由于朋友遇到这个问题,特意上网搜索了很久,没有相关答案,后来自己尝试与能正常显示的做设置对比,才找到控制开关,在此做个记录,分享给遇到这个问题的朋友. 问题如下图: 解决办法: 左上角File--&g ...
- Spring Cloud微服务系统下的数据一致性探讨
我想这个问题需要根据自己的系统具体架构来分别讨论,这边拿一个车联网的系统举例. 拆除GPS这个功能接口需要分几个步骤实现(不涉及数据更新的步骤略去了): ①更改GPS设备状态(设备管理服务) ②更改工 ...