Daimayuan Online Judge 线段树2
给
支持
- 1 x d ,修改
。 - 2 l r ,查询
中的最大子段和。
一:确定需要维护的信息。根据分治中线讨论,哪些信息可以合并出所需信息。递归讨论新信息如何合并。直至完全拆解。
- 不越过分治中线:
的最大子段和,要么是 的最大子段和,要么是 的最大子段和。 - 越过分治中线:
的最大后缀和 + 的最大前缀和。 - 递归讨论
的最大后缀和最大前缀如何维护:- 不越过分治中线:
的最大后缀和为 的最大后缀和; 的最大前缀和为 的最大前缀和。 - 越过分治中线:
的最大后缀和为 的最大后缀和 + 的和; 的最大前缀和为 的最大前缀和 + 的和。 - 递归讨论
的和如何维护: 的和显然越过分治中线,为 的和 + 的和。不再产生新信息。
- 不越过分治中线:
- 补充:
时 信息与 和 的信息独立,不需要考虑 信息更新的顺序。
struct Info { long long mss, mpre, msuf, s; // 最大子段和,最大前缀和,最大后缀和,区间和 }; struct Node { Info f; } seg[N * 4]; Info operator + (const Info &l, const Info &r) { Info ret; ret.mss = std::max({l.mss, r.mss, l.sufs + r.pres}); ret.pres = std::max(l.mpre, l.s + r.mpre); ret.sufs = std::max(r.msuf, l.msuf + r.s); ret.s = l.s + r.s; return ret; } void update(int id) { seg[id].f = seg[ id * 2 ].f + seg[ id * 2 + 1 ].f; }
二:完成主程序框架
int main() { int n, q; std::cin >> n >> q; for (int i = 1; i <= n; i++) std::cin >> a[i]; build(1, 1, n); for (int i = 1; i <= q; i++) { int typ; std::cin >> typ; if ( typ == 1 ) { int x, d; std::cin >> x >> d; change(1, 1, n, x, d); } else { int l, r; std::cin >> l >> r; auto ans = query(1, 1, n, l, r); std::cout << ans.mss << '\n'; } } return 0; }
三:完成建树、查询、单点修改(实际上只有建树递归到点上初始化信息、单点修改递归到点上修改信息的代码有变化)
void build(int id, int l, int r) { if (l == r) { seg[id].f = {a[l], a[l], a[l], a[l]}; } else { int mid = ( l + r ) >> 1; build( id * 2, l, mid ); build (id * 2 + 1, mid + 1, r ); update(id); } } Info query(int id, int l, int r, int ql, int qr) { if ( l == ql && r == qr ) { return seg[id].f; } else { int mid = ( l + r ) >> 1; if (qr <= mid) return query( id * 2, l, mid, ql, qr ); else if (ql > mid) return query( id * 2 + 1, mid + 1, r, ql, qr ); else return query( id * 2, l, mid, ql, mid ) + query( id * 2 + 1, mid + 1, r, mid + 1, qr ); } } void change(int id, int l, int r, int pos, int d) { if ( l == r ) { seg[id].f = {d, d, d, d}; } else { int mid = ( l + r ) >> 1; if ( pos <= mid ) change( id * 2, l, mid, pos, d ); else change( id * 2 + 1, mid + 1, r, pos, d ); update(id); } }
完整代码
view
#include <bits/stdc++.h> const int N = 200005; int a[N]; struct Info { long long mss, mpre, msuf, s; // 最大子段和,最大前缀和,最大后缀和,区间和 }; struct Node { Info f; } seg[N * 4]; Info operator + (const Info &l, const Info &r) { Info ret; ret.mss = std::max({l.mss, r.mss, l.msuf + r.mpre}); ret.mpre = std::max(l.mpre, l.s + r.mpre); ret.msuf = std::max(r.msuf, l.msuf + r.s); ret.s = l.s + r.s; return ret; } void update(int id) { seg[id].f = seg[ id * 2 ].f + seg[ id * 2 + 1 ].f; } void build(int id, int l, int r) { if (l == r) { seg[id].f = {a[l], a[l], a[l], a[l]}; } else { int mid = ( l + r ) >> 1; build( id * 2, l, mid ); build (id * 2 + 1, mid + 1, r ); update(id); } } Info query(int id, int l, int r, int ql, int qr) { if ( l == ql && r == qr ) { return seg[id].f; } else { int mid = ( l + r ) >> 1; if (qr <= mid) return query( id * 2, l, mid, ql, qr ); else if (ql > mid) return query( id * 2 + 1, mid + 1, r, ql, qr ); else return query( id * 2, l, mid, ql, mid ) + query( id * 2 + 1, mid + 1, r, mid + 1, qr ); } } void change(int id, int l, int r, int pos, int d) { if ( l == r ) { seg[id].f = {d, d, d, d}; } else { int mid = ( l + r ) >> 1; if ( pos <= mid ) change( id * 2, l, mid, pos, d ); else change( id * 2 + 1, mid + 1, r, pos, d ); update(id); } } int main() { int n, q; std::cin >> n >> q; for (int i = 1; i <= n; i++) std::cin >> a[i]; build(1, 1, n); for (int i = 1; i <= q; i++) { int typ; std::cin >> typ; if ( typ == 1 ) { int x, d; std::cin >> x >> d; change(1, 1, n, x, d); } else { int l, r; std::cin >> l >> r; auto ans = query(1, 1, n, l, r); std::cout << ans.mss << '\n'; } } return 0; }
——永远是挑战而不是练习,下次一定更好。
分类:
数据结构 / 线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现