兴安盟网站建设_网站建设公司_数据备份_seo优化
2026/1/20 10:39:53 网站建设 项目流程

引言

该问题几乎包含了所有的splaysplaysplay操作, 假设不了解splaysplaysplay可以单击这里

题目-维护数列

问题分析

因为涉及到区间翻转操作, 线段树无法实现(线段树解决的是区间属性问题)

其实最复杂的操作是求区间的最大
子段和
, 可以考虑splaysplaysplay维护的节点信息

splaysplaysplay每个节点表示一个数字, 多个点构成的的中序遍历就是希望求的序列, 因此序列就是中序遍历维护的

算法步骤

splaysplaysplay维护的节点信息

  • 维护最大子段和,maxv,lm,rm,summaxv, lm, rm, summaxv,lm,rm,sum
  • 节点儿子, 父节点信息s,ps, ps,p, 当前节点的权值vvv
  • 是否翻转revrevrev
  • 查询节点的前驱和后继cntcntcnt
  • 整个区间是否变成相同的数samesamesame

实现细节

如果一个点有延迟标记, 这个点的权值存储的是执行延迟标记之前的值还是执行延迟标记之后的值需要自己去定义

因为执行samesamesame或者revrevrev延迟标记, 会对当前节点的值(maxv,lm,rm,summaxv, lm, rm, summaxv,lm,rm,sum)产生影响, 能够定义当前节点的值(maxv,lm,rm,summaxv, lm, rm, summaxv,lm,rm,sum)是延迟标记操作之后的值

具体的来说

对于当前节点, 如果打上了延迟标记, 那么将该节点的maxv,lm,rm,summaxv, lm, rm, summaxv,lm,rm,sum都计算一遍


并且在节点执行push down延迟操作的时候, 不仅仅是直接将子节点打上标记, 而且将子节点的maxv,lm,rm,summaxv, lm, rm, summaxv,lm,rm,sum计算一遍

在删除过程中需要进行内存回收优化内存将删除的节点就是, 也就回收到节点池

因此初始化的时候, ms = sum = v, 不能是max(v, 0)

代码实现

注意事项:

  • 计算跨区间的情况, 需要加当前节点的值vvv
  • 注意内存池的指针变量不要和父节点变量ppp重名
  • 因为有哨兵节点的存在, 注意get_k()的参数
  • 延迟标记的处理, 规定若是当前对某个子树打上延迟标记, 对于当前节点立刻生效
  • 题目要求最大子段和最少囊括一个点, 因此初始化ms的时候, 不能设置为max⁡(v,0)\max(v, 0)max(v,0), 而是没有选择的设置为vvv
  • 000号点是边界哨兵节点, 因此初始化节点池的时候, 必须从111开始
#include <bits/stdc++.h>using namespace std;const int N = 5e5 + 10, INF = 1e9;int n, m;struct Node {int s[2], p, v;int rev, same, cnt;int ms, ls, rs, sum;// 因为内存回收机制的存在, 必须在此刻重置rev和same的延迟标记void init(int _v, int _p) {s[0] = s[1] = 0;p = _p, v = _v;cnt = 1;rev = same = 0;sum = ms = v;ls = rs = max(v, 0);}} tr[N];// nodes作为节点池, ptr分配节点int root, nodes[N], ptr;int w[N];void pushup(int u) {Node &lson = tr[tr[u].s[0]], &rson = tr[tr[u].s[1]];tr[u].cnt = lson.cnt + rson.cnt + 1;tr[u].sum = lson.sum + rson.sum + tr[u].v;tr[u].ls = max(lson.ls, lson.sum + tr[u].v + rson.ls);tr[u].rs = max(rson.rs, rson.sum + tr[u].v + lson.rs);// 注意需要加当前节点的值tr[u].ms = max({lson.ms, rson.ms, lson.rs + tr[u].v + rson.ls});}void pushdown(int u) {Node &lson = tr[tr[u].s[0]], &rson = tr[tr[u].s[1]];if (tr[u].same) {tr[u].same = tr[u].rev = 0;if (tr[u].s[0]) {lson.same = 1;lson.v = tr[u].v;lson.sum = tr[u].v * lson.cnt;if (tr[u].v > 0) lson.ms = lson.ls = lson.rs = lson.sum;else {lson.ms = tr[u].v;lson.ls = lson.rs = 0;}}if (tr[u].s[1]) {rson.same = 1;rson.v = tr[u].v;rson.sum = tr[u].v * rson.cnt;if (tr[u].v > 0) rson.ms = rson.ls = rson.rs = rson.sum;else {rson.ms = tr[u].v;rson.ls = rson.rs = 0;}}}// 当子树的根被打上标记, 约定翻转, 这里就不需要翻转else if (tr[u].rev) {tr[u].rev = 0;lson.rev ^= 1, rson.rev ^= 1;swap(lson.ls, lson.rs), swap(rson.ls, rson.rs);swap(lson.s[0], lson.s[1]), swap(rson.s[0], rson.s[1]);}}void rotate(int x) {int y = tr[x].p, z = tr[y].p;int k = tr[y].s[1] == x;tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z;tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;tr[x].s[k ^ 1] = y, tr[y].p = x;pushup(y), pushup(x);}void splay(int x, int k) {while (tr[x].p != k) {int y = tr[x].p, z = tr[y].p;if (z != k) {if ((tr[z].s[1] == y) ^ (tr[y].s[1] == x)) rotate(x);else rotate(y);}rotate(x);}if (!k) root = x;}// 将一段序列构建二叉树int build(int l, int r, int p) {int mid = l + r >> 1;int u = nodes[ptr--];tr[u].init(w[mid], p);if (l < mid) tr[u].s[0] = build(l, mid - 1, u);if (r > mid) tr[u].s[1] = build(mid + 1, r, u);pushup(u);return u;}int get_k(int k) {int u = root;while (u) {pushdown(u);int cnt = tr[tr[u].s[0]].cnt + 1;if (cnt > k) u = tr[u].s[0];else if (cnt == k) return u;else u = tr[u].s[1], k -= cnt;}return 0;}// 内存回收void release(int u) {if (tr[u].s[0]) release(tr[u].s[0]);if (tr[u].s[1]) release(tr[u].s[1]);nodes[++ptr] = u;}int main() {ios::sync_with_stdio(false);cin.tie(0);// 所有点是可用的for (int i = 1; i < N; ++i) nodes[++ptr] = i;cin >> n >> m;for (int i = 1; i <= n; ++i) cin >> w[i];// 为了保证数列时刻都有数字以及如果当前节点没有左右儿子节点不会造成影响tr[0].ms = w[0] = w[n + 1] = -INF;// 原序列初始化为树root = build(0, n + 1, 0);string op;while (m--) {cin >> op;if (op == "INSERT") {int posi, tot;cin >> posi >> tot;int u = get_k(posi + 1), v = get_k(posi + 2);splay(u, 0), splay(v, u);for (int i = 0; i < tot; ++i) cin >> w[i];tr[v].s[0] = build(0, tot - 1, v);pushup(v), pushup(u);}else if (op == "DELETE") {int posi, tot;cin >> posi >> tot;int u = get_k(posi), v = get_k(tot + posi + 1);splay(u, 0), splay(v, u);release(tr[v].s[0]);tr[v].s[0] = 0;pushup(v), pushup(u);}else if (op == "MAKE-SAME") {int posi, tot, c;cin >> posi >> tot >> c;int u = get_k(posi), v = get_k(tot + posi + 1);splay(u, 0), splay(v, u);Node &son = tr[tr[v].s[0]];son.same = 1;son.v = c;son.sum = son.cnt * c;if (c > 0) son.ms = son.ls = son.rs = son.sum;else {son.ms = c;son.ls = son.rs = 0;}pushup(v), pushup(u);}else if (op == "REVERSE") {int posi, tot;cin >> posi >> tot;int u = get_k(posi), v = get_k(tot + posi + 1);splay(u, 0), splay(v, u);Node &son = tr[tr[v].s[0]];son.rev ^= 1;swap(son.ls, son.rs);swap(son.s[0], son.s[1]);pushup(v), pushup(u);}else if (op == "GET-SUM") {int posi, tot;cin >> posi >> tot;int u = get_k(posi), v = get_k(tot + posi + 1);splay(u, 0), splay(v, u);cout << tr[tr[v].s[0]].sum << '\n';pushup(v), pushup(u);}else {cout << tr[root].ms << '\n';}}return 0;}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询