P2572 序列操作
题目链接
需要实现区间覆盖,区间01取反,区间求和以及区间查询最大连续段。区间覆盖很好实现,区间01取反只需要用分别统计01个数的时候将他俩交换就可以了,区间求和在取反之后只需要len−sum就可以求出来了。重点就是区间最大连续子段,分成三类:
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 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/Haven-/p/16644247.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现