【序列操作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表示询问 ...
随机推荐
- 洛谷 P1097 统计数字
P1097 统计数字 题目描述 某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9).已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自 ...
- amazeui学习笔记--css(常用组件13)--进度条Progress
amazeui学习笔记--css(常用组件13)--进度条Progress 一.总结 1.进度条基本使用:进度条组件,.am-progress 为容器,.am-progress-bar 为进度显示信息 ...
- 【例题 6-12 UVA - 572 】Oil Deposits
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] dfs.. [代码] #include <bits/stdc++.h> using namespace std; con ...
- windows 控制台下 无法获取完整的回车键值
问题描述: 收集的网友分析: http://bbs.csdn.net/topics/370084904 因为C语言和UNIX的开发者是同事…… C语言里统一用的\n表示另起一行.微软的DOS受到了当时 ...
- python opencv3 —— 改变颜色空间(color space)
OpenCV: Changing Colorspaces 1. 查看 opencv 支持的颜色空间转换 opencv 中色彩空间转换由一些定义的全局的宏给出,使用如下的代码,将它们调出: >&g ...
- Makefile中支持的函数大全
一.描述 Makefile的函数调用,很像变量的使用,也是以"$"来标识的,其语法如下: $(<function> <arguments> ) 或是 ${& ...
- 【redis,1】java操作redis: 将string、list、map、自己定义的对象保存到redis中
一.操作string .list .map 对象 1.引入jar: jedis-2.1.0.jar 2.代码 /** * @param args */ public s ...
- js进阶课程 12-9 jquery的事件对象event的方法有哪些?
js进阶课程 12-9 jquery的事件对象event的方法有哪些? 一.总结 一句话总结:三组六个,阻止默认事件一组,阻止冒泡一组,阻止冒泡和剩余事件一组. 1.事件的默认动作指什么? 比如点a标 ...
- [Angular Unit Testing] Debug unit testing -- component rendering
If sometime you want to log out the comonent html to see whether the html render correctly, you can ...
- strace跟踪线程调用
方法一:strace -fp pid , 可以跟踪所有线程, 进程的系统调用. [root@xxxx]strace -p 24091 Process xxx attached - interrupt ...