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

10 10
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

5
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]序列操作_线段树的更多相关文章

  1. BZOJ1858 [Scoi2010]序列操作(线段树)

    题目链接 [Scoi2010]序列操作 考验代码能力的一道好题. 思想还是很简单的(直接上线段树),但是比较难写. #include <bits/stdc++.h> using names ...

  2. [SCOI2010]序列操作 BZOJ1858 线段树

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

  3. [bzoj2962]序列操作_线段树_区间卷积

    序列操作 bzoj-2962 题目大意:给定一个n个数的正整数序列,m次操作.支持:1.区间加:2.区间取相反数:3.区间求选c个数的乘积和. 注释:$1\le n,m\le 5\cdot 10^4$ ...

  4. BZOJ_2962_序列操作_线段树

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

  5. bzoj 1858: [Scoi2010]序列操作【线段树】

    合并中间那块的时候没取max--WAWAWA 在线段树上维护一堆东西,分别是len区间长度,sm区间内1的个数,ll0区间从左开始最长连续0,ml0区间中间最长连续0,rl0区间从右开始最长连续0,l ...

  6. 【BZOJ1858】序列操作(线段树)

    [BZOJ1858]序列操作(线段树) 题面 BZOJ 题解 这题思路很简单,细节很烦,很码 维护区间翻转和区间赋值标记 当打到区间赋值标记时直接覆盖掉翻转标记 下放标记的时候先放赋值标记再放翻转标记 ...

  7. 【BZOJ2962】序列操作(线段树)

    [BZOJ2962]序列操作(线段树) 题面 BZOJ 题解 设\(s[i]\)表示区间内选择\(i\)个数的乘积的和 考虑如何向上合并? \(s[k]=\sum_{i=0}^klson.s[i]*r ...

  8. bzoj1858SCOI 序列操作 (线段树)

    题目大意: 给定一个长度为n的01序列为,现在有m种操作 \(0\ a\ b\) 把\([a,b]\)的数全部修改为0 \(1\ a\ b\) 把\([a,b]\)的数全部修改为1 \(2\ a\ b ...

  9. 序列操作 BZOJ2962 线段树

    分析: 数据范围表示:c特别的小(c<20) 我们可以考虑nlogn*c^2的算法. 线段树维护区间信息:f[i]表示在[l,r]这段区间中选择i个数相乘的和. 因此,我们可以将区间看成一个点, ...

随机推荐

  1. Dapper.SimpleCRUD mysql 插入数据时出现的小插曲

    最近想玩一下.net dapper,然后在nuget包中搜索看到了 Dapper.SimpleCRUD ,然后我等好奇心重的小骚年,内心又开始跃跃欲试. 使用sqlserver数据库时没有遇到问题,既 ...

  2. Go中string转[]byte的陷阱

    Go中string转[]byte的陷阱html {overflow-x: initial !important;}#write, body { height: auto; }#write, #writ ...

  3. MLDS笔记:Generalization

    1 泛化能力 用VC维来衡量一个模型的表达能力,比如2维线性模型的VC维为3. 在图1-2中,随便给啥训练数据该model都能learn起来. 从理论上来看,当2个model在训练数据上表现一样时,为 ...

  4. C++string函数之strcpy_s

    strcpy_s和strcpy()函数的功能几乎是一样的.strcpy函数,就象gets函数一样,它没有方法来保证有效的缓冲区尺寸,所以它只能假定缓冲足够大来容纳要拷贝的字符串.在程序运行时,这将导致 ...

  5. 《Linux下FTP服务器搭建及FTP使用》

    .LOGAndy:mxtd114 <Linux下FTP服务器搭建> 0.root登录 1.安装ftp # yum -y install ftp 2.安装vsftpd # yum -y in ...

  6. 浅谈编程语言中的新宠Python,你叫它如何不火?

    论述 凡是对编程有所关注的朋友都已经知道,Python公布于1991年,即使出现的时间不是很遥远,但是在众多爱好者的贡献下已经发展到全民Python的地步. Python最近火起来的笼统原因:面向企业 ...

  7. 重温《STL源码剖析》笔记 第四章

    源码之前,了无秘密  ——侯杰 序列式容器 关联式容器 array(build in) RB-tree vector set heap   map priority-queue multiset li ...

  8. SQL Server中表锁定的原理及解锁演示

    有几个朋友留言建议结合例子来演示一下, 上篇已经说过锁的几种类型, 可以利用系统动态视图sys.dm_tran_locks查看到,重要的栏位如下: resource_type 被锁的资源类型(Data ...

  9. arcEngine开发之IMapControl接口

    简介 IMapControl接口最重要的是包含IMap属性,还提供另外的属性用于:管理一般的外观显示,管理图层,加载地图文档以及跟踪在界面上显示的图形. 小知识点:一般一个接口的最新实现是 Defau ...

  10. SSM-MyBatis-18:Mybatis中二级缓存和第三方Ehcache配置

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 二级缓存 Mybatis中,默认二级缓存是开启的.可以关闭. 一级缓存开启的.可以被卸载吗?不可以的.一级缓存 ...