!-- Loading 底层遮罩 -->

P4513 小白逛公园

感谢所有AC

传送门

思路

       该题的实质是求解区间最大连续子段和,但显然用dp(复杂度为O(n2))去解会TLE。因此考虑能够支持区间操作的线段树。

       如何用线段树维护一个区间的最大连续子段和呢?先分析一下对于一个父节点,其最大连续子段和的几种可能情况。

       ① 父节点的最大连续子段和就是左子节点的最大连续子段和。

       ② 父节点的最大连续子段和就是右子节点的最大连续子段和。

       ③ 父节点的最大连续子段和就是左子节点的右连续子段和(包括左子节点右端点)和右子节点的左连续子段和(包括右子节点左端点)。(如图)

                     

        对于这三种情况,在维护时需要比较三者大小来取值。那么这颗线段树此时要维护三个值,最大连续子段和,左最大连续子段和,右最大子段和。接下来看如何维护左右最大连续子段和。对于一个父节点的左最大连续子段和来说,有两种组合情况,如下图:

                     

                     

         这里发现第二种情况需要用到左子节点区间总和,那么该线段树要再维护一个区间和。这样就建立了一棵能够维护最大连续子段和的线段树。

         讲完建树和维护,说说单点修改和查询。这个线段树的单点修改与平时无异,关键在于查询。如何查询一个区间的最大连续子段和?还是像以前一样分割为小区间求和吗?显然这样的查询方式不适用于最大连续子段和这种信息,小区间之间可能存在断点导致无法直接合并。小知识:遇到这种情况时不妨考虑改变查询的返回值。由于该线段树的信息有四个,我们用一个结构体去保存,那么是否可以定义一个结构体,去整合查询区间分割形成的小区间的信息,就像最初维护线段树时那样,这样该结构体就保存了待查询区间的四个信息,答案显然。

         代码细节上需要注意查询时要保证有返回值,否则在整合两个结构体信息时会出现无法访问的情况而导致RE。

代码

#include<iostream> #define maxn 500007 using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); } return x * f; } int n, m, a[maxn], p, s, op; struct node { int sum, val, lv, rv; }t[maxn<<2]; void pushup(int u) { int ls = u << 1, rs = u << 1 | 1; t[u].sum = t[ls].sum + t[rs].sum; t[u].val = max(max(t[ls].val, t[rs].val), t[ls].rv + t[rs].lv); t[u].lv = max(t[ls].lv, t[ls].sum + t[rs].lv); t[u].rv = max(t[rs].rv, t[rs].sum + t[ls].rv); } void build(int u, int l, int r) { if (l == r) t[u].sum = t[u].val = t[u].lv = t[u].rv = a[l]; else { int m = l + r >> 1; build(u << 1, l, m), build(u << 1 | 1, m + 1, r); pushup(u); } } void update(int u, int l, int r, int p, int s) { if (l == r) t[u].sum = t[u].val = t[u].rv = t[u].lv = s; else { int m = l + r >> 1; if (m >= p) update(u << 1, l, m, p, s); else update(u << 1 | 1, m + 1, r, p, s); pushup(u); } } node query(int u, int l, int r, int L, int R) { if (L <= l && r <= R) return t[u]; int m = l + r >> 1; if (R <= m) return query(u << 1, l, m, L, R); if (L > m) return query(u << 1 | 1, m + 1, r, L, R); if (L <= m && m < R) { node res = { 0 }; node ls = query(u << 1, l, m, L, m), rs = query(u << 1 | 1, m + 1, r, m + 1, R); res.sum = ls.sum + rs.sum; res.val = max(max(ls.val, rs.val), ls.rv + rs.lv); res.lv = max(ls.lv, ls.sum + rs.lv); res.rv = max(rs.rv, rs.sum + ls.rv); return res; } } int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); n = read(), m = read(); for (int i = 1; i <= n; i++) a[i] = read(); build(1, 1, n); while (m--) { op = read(), p = read(), s = read(); if (op == 1) { node ans = query(1, 1, n, min(p, s), max(p, s)); cout << ans.val << '\n'; } else update(1, 1, n, p, s); } return 0; }

 


__EOF__

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