题目描述

Lxhgww 最近收到了一个 01 序列,序列里面包含了 n(1≤n≤105)个数,这些书要么是 0,要么是 1,现在对这个序列有五种变换操作和询问操作:
1. 0 a b ,把[a,b]区间内所有数全部变成 0。
2. 1 a b ,把[a,b]区间内所有数全部变成 1。
3. 2 a b ,把[a,b]区间内所有数全部取反,也就是说把所有的 0 变成 1,把所有的 1 变成 0。
4. 3 a b ,询问[a,b]区间内总共有多少个 1。
5. 4 a b ,询问[a,b]区间内最多有多少个连续的 1。
对于每一种询问操作,Lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?

输入格式

输入数据第一行包括 2 个数,n 和 m(1≤m≤105)分别表示序列的长度和操作数目。
第二行包括 n 个数,表示序列的初始状态.
接下来 m 行,每行 3 个数,op,a,b(0≤op≤4,0≤a≤b<n),表示对于区间[a,b]执行标号为 op 的操作。

输出格式

对于每次询问,输出单独的一行表示答案。

样例数据 1

输入

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

输出




5

题目分析

  线段树裸题,关于区间最大连续的问题,都是维护左端最长连续,右端最长连续,和总的最长连续,更新即可。

  比较坑的是下标的下放顺序:无论是否有反转标记都可以直接覆盖,把反转标志置为false。但若是有覆盖标记,就必须先进行覆盖标记的下传,再进行反转。

code

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std; const int N = 1e5 + ;
int n, m, data[N];
struct node{
int len, cnt, tag;
bool rev;
int lx0, rx0, lx1, rx1, mx0, mx1;
node():tag(-){}
};
inline void wr(int);
namespace SegTree{
node tr[N << ];
inline void upt(int k){
tr[k].cnt = tr[k << ].cnt + tr[k << | ].cnt;
tr[k].lx0 = tr[k << ].lx0, tr[k].lx1 = tr[k << ].lx1;
tr[k].rx0 = tr[k << | ].rx0, tr[k].rx1 = tr[k << | ].rx1;
if(tr[k << ].cnt == tr[k << ].len)
tr[k].lx1 += tr[k << | ].lx1;
if(tr[k << ].cnt == )
tr[k].lx0 += tr[k << | ].lx0;
if(tr[k << | ].cnt == tr[k << | ].len)
tr[k].rx1 += tr[k << ].rx1;
if(tr[k << | ].cnt == )
tr[k].rx0 += tr[k << ].rx0;
tr[k].mx0 = max(tr[k << ].mx0, tr[k << | ].mx0);
tr[k].mx0 = max(tr[k].mx0, tr[k << ].rx0 + tr[k << | ].lx0);
tr[k].mx1 = max(tr[k << ].mx1, tr[k << | ].mx1);
tr[k].mx1 = max(tr[k].mx1, tr[k << ].rx1 + tr[k << | ].lx1);
}
inline void cover(int , int);
inline void Rev(int k){
if(tr[k].tag != -){
if(tr[k].len > )
cover(k << , tr[k].tag),
cover(k << | , tr[k].tag);
tr[k].tag = -;
}
tr[k].cnt = tr[k].len - tr[k].cnt;
swap(tr[k].lx1, tr[k].lx0);
swap(tr[k].rx1, tr[k].rx0);
swap(tr[k].mx0, tr[k].mx1);
tr[k].rev ^= ;
}
inline void cover(int k, int v){
tr[k].rev = ;
tr[k].cnt = tr[k].lx1 = tr[k].rx1 = tr[k].mx1 = (v == ) * tr[k].len;
tr[k].lx0 = tr[k].rx0 = tr[k].mx0 = (v == ) * tr[k].len;
tr[k].tag = v;
}
inline void pushdown(int k){
if(tr[k].tag != -){
if(tr[k].len > )
cover(k << , tr[k].tag),
cover(k << | , tr[k].tag);
tr[k].tag = -;
}
if(tr[k].rev){
tr[k].rev = ;
if(tr[k].len > )
Rev(k << ),
Rev(k << | );
}
}
inline int queryCnt(int k, int l, int r, int x, int y){
pushdown(k);
if(x <= l && r <= y)
return tr[k].cnt;
int mid = l + r >> , ret = ;
if(x <= mid) ret += queryCnt(k << , l, mid, x, y);
if(y > mid) ret += queryCnt(k << | , mid + , r, x, y);
return ret;
}
inline node queryMx(int k, int l, int r, int x, int y){
pushdown(k);
if(l == x && r == y) return tr[k];
int mid = l + r >> ;
if(y <= mid) return queryMx(k << , l, mid, x, y);
else if(x > mid) return queryMx(k << | , mid + , r, x, y);
else{
node ret1 = queryMx(k << , l, mid, x, mid);
node ret2 = queryMx(k << | , mid + , r, mid + , y);
node ret;
ret.lx1 = ret1.lx1;
ret.rx1 = ret2.rx1;
if(ret1.cnt == ret1.len)
ret.lx1 += ret2.lx1;
if(ret2.cnt == ret2.len)
ret.rx1 += ret1.rx1;
ret.mx1 = max(ret1.mx1,ret2.mx1);
ret.mx1 = max(ret.mx1, ret1.rx1 + ret2.lx1);
return ret;
}
}
inline void build(int k, int l, int r){
tr[k].len = r - l + ;
if(l == r){
tr[k].lx1 = tr[k].rx1 = tr[k].mx1 = tr[k].cnt = (data[l] == );
tr[k].lx0 = tr[k].rx0 = tr[k].mx0 = (data[l] == );
tr[k].rev = ;
tr[k].tag = -;
return;
}
int mid = l + r >> ;
build(k << , l, mid);
build(k << | , mid + , r);
upt(k);
}
inline void modify(int k, int l, int r, int x, int y, int opt){
pushdown(k);
if(x <= l && r <= y){
switch(opt){
case : cover(k, ); break;
case : cover(k, ); break;
case : Rev(k); break;
}
return;
}
int mid = l + r >> ;
if(x <= mid) modify(k << , l, mid, x, y, opt);
if(y > mid) modify(k << | , mid + , r, x, y, opt);
upt(k);
}
}using namespace SegTree; inline int read(){
int i = , f = ; char ch = getchar();
for(; (ch < '' || ch > '') && ch != '-'; ch = getchar());
if(ch == '-') f = -, ch = getchar();
for(; ch >= '' && ch <= ''; ch = getchar())
i = (i << ) + (i << ) + (ch - '');
return i * f;
} inline void wr(int x){
if(x < ) putchar('-'), x = -x;
if(x > ) wr(x / );
putchar(x % + '');
} int main(){
n = read();
m = read();
for(int i = ; i <= n; i++)
data[i] = read();
build(, , n);
for(int i = ; i <= m; i++){
int opt = read();
int a = read() + , b = read() + ;
if(opt == || opt == || opt == )
modify(, , n, a, b, opt);
else if(opt == ) wr(queryCnt(, , n, a, b)), putchar('\n');
else wr((queryMx(, , n, a, b)).mx1), putchar('\n');
}
return ;
}

【序列操作I】线段树的更多相关文章

  1. BZOJ_1858_[Scoi2010]序列操作_线段树

    BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...

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

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

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

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

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

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

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

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

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

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

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

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

  8. 序列操作 BZOJ2962 线段树

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

  9. 2019.01.04 bzoj2962: 序列操作(线段树+组合数学)

    传送门 线段树基础题. 题意:要求维护区间区间中选择ccc个数相乘的所有方案的和(c≤20c\le20c≤20),支持区间加,区间取负. 由于c≤20c\le20c≤20,因此可以对于每个线段树节点可 ...

  10. BZOJ_2962_序列操作_线段树

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

随机推荐

  1. Python数据结构同Json类型数据相互转换的用法

    在做Python接口自动化的时候,经常要用到Python数据结构同Json类型数据相互转换来供我们做进一步的验证提供数据,在此做个记录和总结 Python数据结构同Json类型数据相互转换的函数有:j ...

  2. jQuery中$(document).ready()和window.onload的区别?

    document.ready和document.load的区别?(JQ中的$(document).ready()和window.onload的区别?) window.onload,是采用DOM0级事件 ...

  3. Android ListView带CheckBox实现单选

    第1种方法: 首先是我们的bean: public class Bean { private boolean isChecked; private String msg = "这是一条测试数 ...

  4. 基于element ui的图片预览插件

    写插件很简单,满足两个条件即可,一.基本的逻辑思路,二.熟悉插件语法要求.本次Vue插件也比较简单,点击“查看图片”用轮播的方式限制用户上传的图片,如图: 项目采用的是vue-element-admi ...

  5. md5解密猜想

    md5解密猜想 一.总结 一句话总结:可以用有技巧性(常用密码,相关信息)的暴力破解. 二.md5解密猜想 1.暴力破解 其实md5也是由那些常用的字符串组组成的32位密文,所以可以把那些常用字符串( ...

  6. error: { "$err" : "not master and slaveOk=false", "code" : 13435 }

    rsguo:SECONDARY> db.users.find();error: { "$err" : "not master and slaveOk=false&q ...

  7. mysql 查询重复 去除重复等等

    查找所有重复标题的记录: SELECT * FROM t_info a WHERE ((SELECT COUNT(*) FROM t_info WHERE Title = a.Title) >  ...

  8. angular自定义管道

    原文地址 https://www.jianshu.com/p/5140a91959ca 对自定义管道的认识 管道的定义中体现了几个关键点: 1.管道是一个带有“管道元数据(pipe metadata) ...

  9. [ES7] Handle Errors in Asynchronous Functions

    This lesson shows how regular control flow statements such as try/catch blocks can be used to proper ...

  10. SharedPreferences基础 分类: H1_ANDROID 2013-11-04 22:35 2559人阅读 评论(0) 收藏

    见归档项目:SharedPreferencesDemo.zip 1.对于数据量较小,且有明显的K-V形式的数据而言,适合用SharedPreferences保存.SharedPreferences的数 ...