题目描述

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. 【Codeforces Round #446 (Div. 2) B】Wrath

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 倒着来,维护一个最小的点就可以了. [代码] #include <bits/stdc++.h> using namesp ...

  2. HDU1969 Pie(二分搜索)

    题目大意是要办生日Party,有n个馅饼,有f个朋友.接下来是n个馅饼的半径.然后是分馅饼了, 注意咯自己也要,大家都要一样大,形状没什么要求,但都要是一整块的那种,也就是说不能从两个饼中 各割一小块 ...

  3. 硬件——nrf51822第一篇,GPIO的使用

    未完,待续...... 本实现是基于一个开发箱,包括:综合应用开发系统主板XT-EDU-AK   1套: 手持终端系统 XT-EDU-HK 1套: GPIO操作 工程: 这是一个关于流水灯的程序: 我 ...

  4. 【转】CentOS/RHEL/OracleLinux使用UDEV配置ASMDISK

    转自:http://blog.csdn.net/staricqxyz/article/details/8332566 RHEL 5 / CentOS 5 / Oracle Linux 5 [root@ ...

  5. 【Educational Codeforces Round 31 A】Book Reading

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 水模拟 [代码] #include <bits/stdc++.h> using namespace std; const ...

  6. x=min(x, y)

    x = min(x, y); ⇒ 当然 y 会有多个值传递进来 minHeight = min(minHeight, h[i]); 置于循环之中,不断将当前得到的最小高度值和新加入进来的值进行比较: ...

  7. C语言中 / 得到的结果

  8. 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 ...

  9. [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 ...

  10. 【Codeforces Round #185 (Div. 2) C】The Closest Pair

    [链接] 链接 [题意] 让你构造n个点,去hack一种求最近点对的算法. [题解] 让x相同. 那么那个剪枝就不会起作用了. [错的次数] 在这里输入错的次数 [反思] 在这里输入反思 [代码] # ...