【序列操作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表示询问 ...
随机推荐
- 【Codeforces Round #446 (Div. 2) B】Wrath
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 倒着来,维护一个最小的点就可以了. [代码] #include <bits/stdc++.h> using namesp ...
- HDU1969 Pie(二分搜索)
题目大意是要办生日Party,有n个馅饼,有f个朋友.接下来是n个馅饼的半径.然后是分馅饼了, 注意咯自己也要,大家都要一样大,形状没什么要求,但都要是一整块的那种,也就是说不能从两个饼中 各割一小块 ...
- 硬件——nrf51822第一篇,GPIO的使用
未完,待续...... 本实现是基于一个开发箱,包括:综合应用开发系统主板XT-EDU-AK 1套: 手持终端系统 XT-EDU-HK 1套: GPIO操作 工程: 这是一个关于流水灯的程序: 我 ...
- 【转】CentOS/RHEL/OracleLinux使用UDEV配置ASMDISK
转自:http://blog.csdn.net/staricqxyz/article/details/8332566 RHEL 5 / CentOS 5 / Oracle Linux 5 [root@ ...
- 【Educational Codeforces Round 31 A】Book Reading
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 水模拟 [代码] #include <bits/stdc++.h> using namespace std; const ...
- x=min(x, y)
x = min(x, y); ⇒ 当然 y 会有多个值传递进来 minHeight = min(minHeight, h[i]); 置于循环之中,不断将当前得到的最小高度值和新加入进来的值进行比较: ...
- C语言中 / 得到的结果
- 2、在uboot上实现电源管理
tar xjf u-boot-1.1.6.tar.bz2 cd u-boot-1.1.6 patch -p1 < ../u-boot-1.1.6_jz2440.patch make 100ask ...
- [HTML] Change an HTML5 input's placeholder color with CSS
We will look at what CSS selectors to use to change an HTML5 inputs placeholder color. This can diff ...
- 【Codeforces Round #185 (Div. 2) C】The Closest Pair
[链接] 链接 [题意] 让你构造n个点,去hack一种求最近点对的算法. [题解] 让x相同. 那么那个剪枝就不会起作用了. [错的次数] 在这里输入错的次数 [反思] 在这里输入反思 [代码] # ...