NC20279 [SCOI2010]序列操作
题目
题目描述
lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:
0 a b 把[a, b]区间内的所有数全变成0
1 a b 把[a, b]区间内的所有数全变成1
2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0
3 a b 询问[a, b]区间内总共有多少个1
4 a b 询问[a, b]区间内最多有多少个连续的1
对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?
输入描述
输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目
第二行包括n个数,表示序列的初始状态
接下来m行,每行3个数,op, a, b,(0 ≤ op ≤ 4,0 ≤ a ≤ b)
输出描述
对于每一个询问操作,输出一行,包括1个数,表示其对应的答案
示例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
备注
对于30%的数据, ;
对于100%的数据, 。
题解
知识点:线段树。
这一道题维护的信息较多需要逐一分析。
为了方便求区间长度,还有取反的操作,我们将 的信息都维护一下,但接下来只讲 的部分, 同 就不讲了。
首先需要维护的是 的数量 ,以及连续 个数的最大值 。
在合并时, 直接加即可。 不仅要取子区间的 , 还需要考虑左子区间从右端点开始连续的 ,以及右子区间从左端点开始连续的 ,两部分拼起来的长度。因此还需要维护,区间从左端点开始连续 的个数 ,从右端点开始连续 的个数 。
对于 ,在合并时,要考虑一个特殊情况,左子区间 等于区间长度(可用 表示),那么他可以与右子区间的 相加,得到区间的 , 同理。除此之外,直接继承即可。
因此,区间信息需要维护 。
区间修改需要维护三种修改标记:全 、全 、取反。三种的区间修改都十分好实现,前两种直接改为区间长度,取反交换 即可。另外,考虑到标记下传需要一个标记表示没有修改,即单位元值,以供函数特判。
因此,区间修改需要维护 (无修改、全 、全 、取反)。
懒标记的修改需要分类讨论:
- 修改为未修改,则新标记维持原状。
- 修改为全 ,则新标记为全 。
- 修改为全 ,则新标记为全 。
- 修改为取反,则分类讨论:
- 若原标记为未修改,则新标记为取反。
- 若原标记为全 ,则新标记为全 。
- 若原标记为全 ,则新标记为全 。
- 若原标记为取反,则新标记为未修改。
于是所有信息就维护完了。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; struct T { int sum0, sum1; int max0, max1; int left0, left1; int right0, right1; static T e() { return { 0,0, 0,0, 0,0, 0,0 }; } friend T operator+(const T &a, const T &b) { return{ a.sum0 + b.sum0,a.sum1 + b.sum1, max({a.max0,b.max0,a.right0 + b.left0}),max({a.max1,b.max1,a.right1 + b.left1}), a.left0 == a.sum0 + a.sum1 ? a.left0 + b.left0 : a.left0,a.left1 == a.sum0 + a.sum1 ? a.left1 + b.left1 : a.left1, b.right0 == b.sum0 + b.sum1 ? b.right0 + a.right0 : b.right0,b.right1 == b.sum0 + b.sum1 ? b.right1 + a.right1 : b.right1 }; } }; struct F { int op; static F e() { return{ 0 }; } T operator()(const T &x) { if (op == 0) return x; else if (op == 1) return { x.sum0 + x.sum1,0, x.sum0 + x.sum1,0, x.sum0 + x.sum1,0, x.sum0 + x.sum1,0 }; else if (op == 2) return{ 0,x.sum0 + x.sum1, 0,x.sum0 + x.sum1, 0,x.sum0 + x.sum1, 0,x.sum0 + x.sum1 }; else return{ x.sum1,x.sum0, x.max1,x.max0, x.left1,x.left0, x.right1,x.right0 }; } F operator() (const F &g) { if (op == 0) return g; else if (op == 1) return { 1 }; else if (op == 2) return { 2 }; else { if (g.op == 0) return { 3 }; else if (g.op == 1) return { 2 }; else if (g.op == 2) return { 1 }; else return { 0 }; } } }; template<class T, class F> class SegmentTreeLazy { int n; vector<T> node; vector<F> lazy; void push_down(int rt) { node[rt << 1] = lazy[rt](node[rt << 1]); lazy[rt << 1] = lazy[rt](lazy[rt << 1]); node[rt << 1 | 1] = lazy[rt](node[rt << 1 | 1]); lazy[rt << 1 | 1] = lazy[rt](lazy[rt << 1 | 1]); lazy[rt] = F::e(); } void update(int rt, int l, int r, int x, int y, F f) { if (r < x || y < l) return; if (x <= l && r <= y) return node[rt] = f(node[rt]), lazy[rt] = f(lazy[rt]), void(); push_down(rt); int mid = l + r >> 1; update(rt << 1, l, mid, x, y, f); update(rt << 1 | 1, mid + 1, r, x, y, f); node[rt] = node[rt << 1] + node[rt << 1 | 1]; } T query(int rt, int l, int r, int x, int y) { if (r < x || y < l) return T::e(); if (x <= l && r <= y) return node[rt]; push_down(rt); int mid = l + r >> 1; return query(rt << 1, l, mid, x, y) + query(rt << 1 | 1, mid + 1, r, x, y); } public: SegmentTreeLazy(int _n = 0) { init(_n); } SegmentTreeLazy(int _n, const vector<T> &src) { init(_n, src); } void init(int _n) { n = _n; node.assign(n << 2, T::e()); lazy.assign(n << 2, F::e()); } void init(int _n, const vector<T> &src) { init(_n); function<void(int, int, int)> build = [&](int rt, int l, int r) { if (l == r) return node[rt] = src[l], void(); int mid = l + r >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); node[rt] = node[rt << 1] + node[rt << 1 | 1]; }; build(1, 1, n); } void update(int x, int y, const F &f) { update(1, 1, n, x, y, f); } T query(int x, int y) { return query(1, 1, n, x, y); } }; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; vector<T> a(n + 1); for (int i = 1;i <= n;i++) { int x; cin >> x; a[i] = { 1 - x,x,1 - x,x,1 - x,x,1 - x,x }; } SegmentTreeLazy<T, F> sgt(n, a); while (m--) { int op, l, r; cin >> op >> l >> r; l++, r++; if (op == 0) sgt.update(l, r, { 1 }); else if (op == 1) sgt.update(l, r, { 2 }); else if (op == 2) sgt.update(l, r, { 3 }); else if (op == 3) cout << sgt.query(l, r).sum1 << '\n'; else cout << sgt.query(l, r).max1 << '\n'; } return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17368005.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧