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. 【React入门实例(运行于浏览器duan)】

    一.HTML模板 二.ReactDOM.render() ReactDOM.render是React的最基本方法,用于将模板转换为HTML语言,并插入指定的DOM节点. ReactReactDOM.r ...

  2. 1-bit and 2-bit Characters

    We have two special characters. The first character can be represented by one bit 0. The second char ...

  3. sql语言不经常用,复习

    sql语言不经常用,每次再用都隔好久的时间,以致最基本的都想不起来了,只好转一篇记着= - 找的时候方便 SQL分类:  DDL-数据定义语言(CREATE,ALTER,DROP,DECLARE)  ...

  4. 转载 jQueryEasyUI Messager基本使用

    http://www.cnblogs.com/libingql/archive/2011/07/17/2109020.html 一.jQueryEasyUI下载地址 http://www.jeasyu ...

  5. JavaScript设计模式之一封装

    对于熟悉C#和Java的兄弟们,面向对象的三大思想(封装,继承,多态)肯定是了解的,今天我想讲讲如何在Javascript中利用封装这个特性,开讲! 我们会把现实中的一些事物抽象成一个Class并且把 ...

  6. Angular集成UEditor

    1.Ueditor的集成主要通过把UEditor做成一个Component来实现,先上Component代码: import { AfterContentInit, Component, Input, ...

  7. Nginx接收的host值会影响alias的规则匹配

    一般内网接收的HTTP请求都是内网唯一的网关传过来的,nginx的alias匹配会直接使用网关穿过的host值,而不是从URL解析出来的,从而导致的问题是,容器的alias相关Server_name规 ...

  8. html5 下拉刷新(pc+移动网页源码)

    本文demo下载地址:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=1071 本文实现在html5网页中使用下 ...

  9. 专业、稳定的微信域名被封检测API平台!

    裂变程序最佳配套api,实时检测域名在微信中是否被封,防止见红  还在手动测试域名在微信是否可用?你OUT了! API文档:最简单的GET接口调用方式 API响应:毫秒级响应效率,100%准确率 AP ...

  10. Myeclipse使用git

    推荐使用服务器:coding,coding的上传很稳定很快 怎么建仓库: coding 这个服务器呢有个很明显的东西就是太的语言可以是中文的, 点头标签的加号就能进行创建仓库了 点击新建就行了 点击这 ...