感谢所有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__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现