P2572 序列操作

题目链接

  需要实现区间覆盖区间01取反区间求和以及区间查询最大连续段。区间覆盖很好实现,区间01取反只需要用分别统计01个数的时候将他俩交换就可以了,区间求和在取反之后只需要lensum就可以求出来了。重点就是区间最大连续子段,分成三类:
    1.左区间全满且跨越到右区间
    2.右区间全满且跨越到左区间
    3.横跨左右区间但是都未满
  在标记上传的时候需要修改的信息比较多

Info operator + (const Info& a, const Info& b) { Info c; c.siz = a.siz + b.siz; c.sum = a.sum + b.sum; for (int i = 0; i < 2; i++) { c.pre[i] = a.pre[i]; if (i == 1 && a.sum == a.siz) { c.pre[i] += b.pre[i]; } else if (i == 0 && a.sum == 0) { c.pre[i] += b.pre[i]; } c.suf[i] = b.suf[i]; if (i == 1 && b.sum == b.siz) { c.suf[i] += a.suf[i]; } else if (i == 0 && b.sum == 0) { c.suf[i] += a.suf[i]; } c.val[i] = b.pre[i] + a.suf[i]; c.val[i] = std::max(c.val[i], a.val[i]); c.val[i] = std::max(c.val[i], b.val[i]); c.val[i] = std::max(std::max(c.val[i], c.pre[i]), c.suf[i]); } return c; }

  标记下传的时候注意先后顺序,应该是先执行区间覆盖操作,再执行区间反转操作,而且在区间覆盖操作完之后应该是要吧原有的区间翻转的标记清空的。

void settag1(int u, int x) { tr[u].res.sum = x * tr[u].res.siz; tr[u].tag.tag1 = x; tr[u].tag.tag2 = 0; tr[u].res.val[x] = tr[u].res.pre[x] = tr[u].res.suf[x] = tr[u].res.siz; tr[u].res.pre[x ^ 1] = tr[u].res.suf[x ^ 1] = tr[u].res.val[x ^ 1] = 0; } void settag2(int u) { tr[u].res.sum = tr[u].res.siz - tr[u].res.sum; if (~tr[u].tag.tag1) { tr[u].tag.tag1 ^= 1; } else { tr[u].tag.tag2 ^= 1; } std::swap(tr[u].res.val[0], tr[u].res.val[1]); std::swap(tr[u].res.pre[0], tr[u].res.pre[1]); std::swap(tr[u].res.suf[0], tr[u].res.suf[1]); } void push(int u) { if (~tr[u].tag.tag1) { tr[u].tag.tag2 = 0; settag1(u << 1, tr[u].tag.tag1); settag1(u << 1 | 1, tr[u].tag.tag1); tr[u].tag.tag1 = -1; } if (tr[u].tag.tag2) { settag2(u << 1); settag2(u << 1 | 1); tr[u].tag.tag2 = 0; } }

  剩下的就是中规中矩的线段树操作了

#include <bits/stdc++.h> using i64 = long long; #define rep(i,a,n) for (int i = a; i < n; i ++ ) #define per(i,a,n) for (int i = n; i >= a; i -- ) #define all(v) v.begin(), v.end() #define SZ(s) int(s.size()) #define pb push_back #define fi first #define se second //head const int N = 100010; int a[N]; struct Info { int siz, sum; int pre[2], suf[2], val[2]; }; struct Tag { int tag1, tag2; Tag() : tag1(-1), tag2(0) {} }; Info operator + (const Info& a, const Info& b) { Info c; c.siz = a.siz + b.siz; c.sum = a.sum + b.sum; for (int i = 0; i < 2; i++) { c.pre[i] = a.pre[i]; if (i == 1 && a.sum == a.siz) { c.pre[i] += b.pre[i]; } else if (i == 0 && a.sum == 0) { c.pre[i] += b.pre[i]; } c.suf[i] = b.suf[i]; if (i == 1 && b.sum == b.siz) { c.suf[i] += a.suf[i]; } else if (i == 0 && b.sum == 0) { c.suf[i] += a.suf[i]; } c.val[i] = b.pre[i] + a.suf[i]; c.val[i] = std::max(c.val[i], a.val[i]); c.val[i] = std::max(c.val[i], b.val[i]); c.val[i] = std::max(std::max(c.val[i], c.pre[i]), c.suf[i]); } return c; } struct Node { Info res; Tag tag; } tr[N << 2]; void build(int u, int l, int r) { if (l == r) { tr[u].res.pre[a[l]] = tr[u].res.suf[a[l]] = tr[u].res.val[a[l]] = tr[u].res.siz = 1; tr[u].res.sum = a[l]; return ; } int mid = (l + r) >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); tr[u].res = tr[u << 1].res + tr[u << 1 | 1].res; } void settag1(int u, int x) { tr[u].res.sum = x * tr[u].res.siz; tr[u].tag.tag1 = x; tr[u].tag.tag2 = 0; tr[u].res.val[x] = tr[u].res.pre[x] = tr[u].res.suf[x] = tr[u].res.siz; tr[u].res.pre[x ^ 1] = tr[u].res.suf[x ^ 1] = tr[u].res.val[x ^ 1] = 0; } void settag2(int u) { tr[u].res.sum = tr[u].res.siz - tr[u].res.sum; if (~tr[u].tag.tag1) { tr[u].tag.tag1 ^= 1; } else { tr[u].tag.tag2 ^= 1; } std::swap(tr[u].res.val[0], tr[u].res.val[1]); std::swap(tr[u].res.pre[0], tr[u].res.pre[1]); std::swap(tr[u].res.suf[0], tr[u].res.suf[1]); } void push(int u) { if (~tr[u].tag.tag1) { tr[u].tag.tag2 = 0; settag1(u << 1, tr[u].tag.tag1); settag1(u << 1 | 1, tr[u].tag.tag1); tr[u].tag.tag1 = -1; } if (tr[u].tag.tag2) { settag2(u << 1); settag2(u << 1 | 1); tr[u].tag.tag2 = 0; } } // assaign void change(int u, int l, int r, int ln, int rn, int x) { push(u); if (l >= ln && r <= rn) return void(settag1(u, x)); int mid = (l + r) >> 1; if (mid >= ln) change(u << 1, l, mid, ln, rn, x); if (mid < rn) change(u << 1 | 1, mid + 1, r, ln, rn, x); tr[u].res = tr[u << 1].res + tr[u << 1 | 1].res; } void reverse(int u, int l, int r, int ln, int rn) { push(u); if (l >= ln && r <= rn) return void(settag2(u)); int mid = (l + r) >> 1; if (mid >= ln) reverse(u << 1, l, mid, ln, rn); if (mid < rn) reverse(u << 1 | 1, mid + 1, r, ln, rn); tr[u].res = tr[u << 1].res + tr[u << 1 | 1].res; } Info query(int u, int l, int r, int ln, int rn) { if (l >= ln && r <= rn) return tr[u].res; int mid = (l + r) >> 1; push(u); if (mid >= rn) return query(u << 1, l, mid, ln, rn); else if (mid < ln) return query(u << 1 | 1, mid + 1, r, ln, rn); else return query(u << 1, l, mid, ln, rn) + query(u << 1 | 1, mid + 1, r, ln, rn); } signed main() { std::cin.tie(nullptr)->sync_with_stdio(false); int n, m; std::cin >> n >> m; for (int i = 1; i <= n; i++) std::cin >> a[i]; build(1, 1, n); for (int i = 1; i <= m; i ++) { int op, l, r; std::cin >> op >> l >> r; l++, r++; if (op <= 1) { change(1, 1, n, l, r, op); } else if (op == 2) { reverse(1, 1, n, l, r); } else if (op == 3) { std::cout << query(1, 1, n, l, r).sum << "\n"; } else { std::cout << query(1, 1, n, l, r).val[1] << "\n"; } } return 0 ^ 0; }

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16644247.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示