眉目舒展,顺问冬安kiritokazuto

假期数学论文->其实是题解之山海经(三哼经)

kiritokazuto·2022-01-21 08:30·278 次阅读

假期数学论文->其实是题解之山海经(三哼经)

写该题解原因

  • 才不是为了数学论文呢
  • 鉴于这么一道线段树的经典题目,网上的题解少之又少, 所以只能自己上,来这么一 篇小小的题解, 嘛, 加深对线段树的理解吧

题意#

“南山之首日鹊山。其首日招摇之山,临于西海之上,多桂,多金玉。有草焉,其状如韭而青华,其名日祝余,食之不饥……又东三百里,日堂庭之山,多?木,多白猿,多水玉,多黄金。又东三百八十里,日?翼之山,其中多怪兽,水多怪鱼,多白玉,多蝮虫,多怪蛇,名怪木,不可以上。……”《山海经》是以山为纲,以海为线记载古代的河流、植物、动物及矿产等情况,(废话 啊呸,陶冶文化情操
而且每一条记录路线都不会有重复的山出现。某天,你的地理老师想重游《山海经》中的路线,为了简化问题,老师已经把每座山用一个整数表示他对该山的喜恶程度,他想知道第a座山到第b座山的中间某段路(i,j)。能使他感到最满意,即(i,j)这条路上所有山的喜恶度之和是(c,d)(a≤c≤d≤b)最大值。于是老师便向你请教,你能帮助他吗?(其实我不想帮他
值得注意的是,在《山海经》中,第i座山只能到达第i+1座山。

样例输入

输入第1行是两个数,n,m,2≤n≤100000,1≤m≤100000,n表示一共有n座山,m表示老师想查询的数目。
第2行是n个整数,代表n座山的喜恶度,绝对值均小于10000。
以下m行每行有a,b两个数,1≤a≤j≤b≤m,表示第a座山到第b座山。
5 3
5 -6 3 -1 4
1 3
1 5
5 5

样例输出

一共有m行,每行有3个数i,j,s,表示从第i座山到第j座山总的喜恶度为s。显然,对于每个查询,有a≤i≤j≤b,如果有多组解,则输出i最小的,如果i也相等,则输出j最小的解。
1 1 5
3 5 6
5 5 4

题意分析#

- 其实就是维护一个最大连续子段和,但这个题恶心就恶心在它的输出顺序(介个老师莫非有强迫症?)

所以权值相同要求l、r尽量小,所以相同时选左儿子不选右儿子,维护时考虑是否加等号#

思路

从左端点开始有两种情况
1、是左儿子从他的左端点向后延伸的最大子段和
2、是左儿子的区间总和加上右儿子从他的左端点向后延伸的最大子段和
同理从右端点也有两种情况
1、是右儿子从他的右端点向前延伸的最大子段和
2、是右儿子的区间总和加上左儿子从他的右端点向前延伸的最大子段和
中间的画图可知有三种情况
1、是左儿子的中间最大子段和(内部, 不碰端点)
2、是右儿子的中间最大子段和 (内部, 不碰端点)
3、是左儿子从他的右端点向前延伸的最大子段和加上右儿子他的左端点向后延伸的最大子段和(就是给他拼起来)

Code#

first one 介绍变量
点击查看代码
Copy
/* l, r - > 整个区间的左右端点 lcnt, rcnt -> 左子树的最大连续和 和 右子树(区间)的最大连续和 lright, rleft -> 左子树最大连续和的右端点(从左儿子左端点开始)和右子树最大连续和的左端点(从右儿子右端点开始) lid -> 最大子段和左端点(中间那段) rid -> 最大子段和右端点(中间那段) sum -> 结点权值和 dat -> 区间内部最大子段和 ->就是中间的 */ struct tree{ int l, r; int lcnt, rcnt; int lright, rleft; int sum, dat, lid, rid; #define lsp (p << 1) #define rsp (p << 1 | 1) #define mid ((t[p].l + t[p].r) >> 1) }t[maxn << 2];
second one 全部代码精华pushup(参考了别人题解也)
点击查看代码
Copy
void pushup(tree &a, const tree &b, const tree &c) {//a是爹 , b是左子树, c是右子树, 如果加了引用就得加const -> 递归传参(未知问题)-> 我太废物,不大清楚 a.sum = b.sum + c.sum;//维护结点(区间)值 if(b.sum + c.lcnt > b.lcnt) {//即是思路从左端点开始的2 a.lcnt = b.sum + c.lcnt; a.lright = c.lright;//a最右 } else {//即是思路从左端点开始的1 a.lcnt = b.lcnt; a.lright = b.lright; } if (c.rcnt > c.sum + b.rcnt) {//即从右开始的1 a.rcnt = c.rcnt; a.rleft = c.rleft; } else {//即从右开始的2 a.rcnt = c.sum + b.rcnt; a.rleft = b.rleft; } //下面都是中间的 if(c.dat > max(b.dat, b.rcnt + c.lcnt)) { a.dat = c.dat; a.lid = c.lid; a.rid = c.rid; }else { if((b.dat > b.rcnt + c.lcnt) || (b.dat == b.rcnt + c.lcnt && b.lid <= b.rleft)) {//保证输出顺序 a.dat = b.dat; a.lid = b.lid; a.rid = b.rid; }else { a.dat = b.rcnt + c.lcnt; a.lid = b.rleft; a.rid = c.lright; } } }
third one 其他
点击查看代码
Copy
inline void build(int p, int l, int r) { t[p].l = l; t[p].r = r; if (l == r) { cin >> t[p].sum; t[p].dat = t[p].lcnt = t[p].rcnt = t[p].sum; t[p].lid = t[p].rid = t[p].lright = t[p].rleft = l; return; } build(lsp, l, mid); build(rsp, mid + 1, r); pushup(t[p], t[lsp], t[rsp]); } tree query(int p, int L, int R) { if (L <= t[p].l && t[p].r <= R) return t[p]; tree ans; if(R <= mid) ans = query(lsp, L, R); else if(L > mid) ans = query(rsp, L, R); else pushup(ans, query(lsp, L, R), query(rsp, L, R)); return ans; } signed main() { cin >> n >> m; build(1, 1, n); for (int i = 1, x, y; i <= m; i ++) { cin >> x >> y; tree ans = query(1, x, y); cout << ans.lid << " " << ans.rid << " " << ans.dat << endl;; } return 0; }
AC代码无注释
点击查看代码
Copy
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; int n, m; typedef long long LL; struct tree{ int l, r; int lcnt, rcnt; int lright, rleft; int sum, dat, lid, rid; #define lsp (p << 1) #define rsp (p << 1 | 1) #define mid ((t[p].l + t[p].r) >> 1) }t[maxn << 2]; inline void pushup(tree &a, const tree &b, const tree &c) { a.sum = b.sum + c.sum; if(b.sum + c.lcnt > b.lcnt) { a.lcnt = b.sum + c.lcnt; a.lright = c.lright; } else { a.lcnt = b.lcnt; a.lright = b.lright; } if (c.rcnt > c.sum + b.rcnt) { a.rcnt = c.rcnt; a.rleft = c.rleft; } else { a.rcnt = c.sum + b.rcnt; a.rleft = b.rleft; } if(c.dat > max(b.dat, b.rcnt + c.lcnt)) { a.dat = c.dat; a.lid = c.lid; a.rid = c.rid; }else { if((b.dat > b.rcnt + c.lcnt) || (b.dat == b.rcnt + c.lcnt && b.lid <= b.rleft)) { a.dat = b.dat; a.lid = b.lid; a.rid = b.rid; }else { a.dat = b.rcnt + c.lcnt; a.lid = b.rleft; a.rid = c.lright; } } } inline void build(int p, int l, int r) { t[p].l = l; t[p].r = r; if (l == r) { cin >> t[p].sum; t[p].dat = t[p].lcnt = t[p].rcnt = t[p].sum; t[p].lid = t[p].rid = t[p].lright = t[p].rleft = l; return; } build(lsp, l, mid); build(rsp, mid + 1, r); pushup(t[p], t[lsp], t[rsp]); } tree query(int p, int L, int R) { if (L <= t[p].l && t[p].r <= R) return t[p]; tree ans; if(R <= mid) ans = query(lsp, L, R); else if(L > mid) ans = query(rsp, L, R); else pushup(ans, query(lsp, L, R), query(rsp, L, R)); return ans; } signed main() { cin >> n >> m; build(1, 1, n); for (int i = 1, x, y; i <= m; i ++) { cin >> x >> y; tree ans = query(1, x, y); cout << ans.lid << " " << ans.rid << " " << ans.dat << endl;; } return 0; }
我再压个行能不能评全网山海经最短啊(doge)

完结撒花

posted @   kiritokazuto  阅读(279)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
目录