【序列操作I】线段树
题目描述
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
2
6
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】线段树的更多相关文章
- BZOJ_1858_[Scoi2010]序列操作_线段树
BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...
- 【BZOJ1858】序列操作(线段树)
[BZOJ1858]序列操作(线段树) 题面 BZOJ 题解 这题思路很简单,细节很烦,很码 维护区间翻转和区间赋值标记 当打到区间赋值标记时直接覆盖掉翻转标记 下放标记的时候先放赋值标记再放翻转标记 ...
- 【BZOJ2962】序列操作(线段树)
[BZOJ2962]序列操作(线段树) 题面 BZOJ 题解 设\(s[i]\)表示区间内选择\(i\)个数的乘积的和 考虑如何向上合并? \(s[k]=\sum_{i=0}^klson.s[i]*r ...
- [SCOI2010]序列操作 BZOJ1858 线段树
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...
- BZOJ1858 [Scoi2010]序列操作(线段树)
题目链接 [Scoi2010]序列操作 考验代码能力的一道好题. 思想还是很简单的(直接上线段树),但是比较难写. #include <bits/stdc++.h> using names ...
- [bzoj2962]序列操作_线段树_区间卷积
序列操作 bzoj-2962 题目大意:给定一个n个数的正整数序列,m次操作.支持:1.区间加:2.区间取相反数:3.区间求选c个数的乘积和. 注释:$1\le n,m\le 5\cdot 10^4$ ...
- 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个数相乘的和. 因此,我们可以将区间看成一个点, ...
- 2019.01.04 bzoj2962: 序列操作(线段树+组合数学)
传送门 线段树基础题. 题意:要求维护区间区间中选择ccc个数相乘的所有方案的和(c≤20c\le20c≤20),支持区间加,区间取负. 由于c≤20c\le20c≤20,因此可以对于每个线段树节点可 ...
- BZOJ_2962_序列操作_线段树
Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问 ...
随机推荐
- Python数据结构同Json类型数据相互转换的用法
在做Python接口自动化的时候,经常要用到Python数据结构同Json类型数据相互转换来供我们做进一步的验证提供数据,在此做个记录和总结 Python数据结构同Json类型数据相互转换的函数有:j ...
- jQuery中$(document).ready()和window.onload的区别?
document.ready和document.load的区别?(JQ中的$(document).ready()和window.onload的区别?) window.onload,是采用DOM0级事件 ...
- Android ListView带CheckBox实现单选
第1种方法: 首先是我们的bean: public class Bean { private boolean isChecked; private String msg = "这是一条测试数 ...
- 基于element ui的图片预览插件
写插件很简单,满足两个条件即可,一.基本的逻辑思路,二.熟悉插件语法要求.本次Vue插件也比较简单,点击“查看图片”用轮播的方式限制用户上传的图片,如图: 项目采用的是vue-element-admi ...
- md5解密猜想
md5解密猜想 一.总结 一句话总结:可以用有技巧性(常用密码,相关信息)的暴力破解. 二.md5解密猜想 1.暴力破解 其实md5也是由那些常用的字符串组组成的32位密文,所以可以把那些常用字符串( ...
- error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
rsguo:SECONDARY> db.users.find();error: { "$err" : "not master and slaveOk=false&q ...
- mysql 查询重复 去除重复等等
查找所有重复标题的记录: SELECT * FROM t_info a WHERE ((SELECT COUNT(*) FROM t_info WHERE Title = a.Title) > ...
- angular自定义管道
原文地址 https://www.jianshu.com/p/5140a91959ca 对自定义管道的认识 管道的定义中体现了几个关键点: 1.管道是一个带有“管道元数据(pipe metadata) ...
- [ES7] Handle Errors in Asynchronous Functions
This lesson shows how regular control flow statements such as try/catch blocks can be used to proper ...
- SharedPreferences基础 分类: H1_ANDROID 2013-11-04 22:35 2559人阅读 评论(0) 收藏
见归档项目:SharedPreferencesDemo.zip 1.对于数据量较小,且有明显的K-V形式的数据而言,适合用SharedPreferences保存.SharedPreferences的数 ...