当前位置: 首页 > news >正文

洛谷 P4513:小白逛公园 ← 线段树(区间合并)

【题目来源】
https://www.luogu.com.cn/problem/P4513
https://www.acwing.com/problem/content/246/

【题目描述】
小新经常陪小白去公园玩,也就是所谓的遛狗啦…
在小新家附近有一条“公园路”,路的一边从南到北依次排着 n 个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。
一开始,小白就根据公园的风景给每个公园打了分。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第 a 个和第 b 个公园之间(包括 a,b 两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。
那么,就请你来帮小白选择公园吧。

【输入格式】
第一行,两个整数 n 和 m,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来 n 行,每行一个整数,依次给出小白开始时对公园的打分。
接下来 m 行,每行三个整数。其中第一个整数 k 为 1 或 2。
● k=1 表示,小新要带小白出去玩,接下来的两个整数 a 和 b 给出了选择公园的范围(1≤a,b≤n)。测试数据可能会出现 a>b 的情况,需要进行交换;
● k=2表示,小白改变了对某个公园的打分,接下来的两个整数 p 和 s,表示小白对第 p 个公园的打分变成了 s(1≤|s|≤1000)。

【输出格式】
小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。

【输入样例】
5 3
1
2
-3
4
5
1 2 3
2 2 -1
1 2 3

【输出样例】
2
-1​​​​​​​

【数据范围】
对于 100% 的数据,1≤n≤5×10^5,1≤m≤10^5,所有打分都是绝对值不超过 1000 的整数。

【算法分析】
● 本题“洛谷 P4513:小白逛公园”的代码与“AcWing 245. 你能回答这些问题吗”(https://www.acwing.com/problem/content/246/)的代码一样,可以视为同一个问题。

● 核心变量 sum、lmax、rmax、tmax 解析
sum,整个区间的总和
lmax,从区间左端点开始的各个子段的最大子段和(前缀最大和)
rmax,以区间右端点结束的各个子段的最大子段和(后缀最大和)
tmax,整个区间内各个子段的最大子段和各个子段,即前文各个前缀、后缀子段

● 核心变量 sum、lmax、rmax、tmax 示例分析
假设区间是 [1,4],数值为 [-1, 3, -2, 6],则:
sum = -1+3-2+6 = 6(整个区间的总和);
lmax = max (-1, -1+3, -1+3-2, -1+3-2+6) = 6(从区间左端点 1 开始的各个子段的最大子段和);
rmax = max (6, -2+6, 3-2+6, -1+3-2+6) = 6(以区间右端点 4 结束的各个子段的最大子段和);
tmax = 6(整个区间里各个子段的最大子段和是 6)。

● 核心代码 pushup 解析

void pushup(node &u,node &le,node &ri) {// 1.父区间总和 = 左子区间总和 + 右子区间总和(最基础的合并)u.sum = le.sum + ri.sum;// 2.父区间的前缀最大和(lmax):两种情况取最大值// 情况1:只在左子区间里的前缀最大和(le.lmax)// 情况2:左子区间全部取完 + 右子区间的前缀最大和(le.sum + ri.lmax)u.lmax = max(le.lmax, le.sum + ri.lmax);// 3.父区间的后缀最大和(rmax):两种情况取最大值// 情况1:只在右子区间里的后缀最大和(ri.rmax)// 情况2:右子区间全部取完 + 左子区间的后缀最大和(ri.sum + le.rmax)u.rmax = max(ri.rmax, ri.sum + le.rmax);// 4.父区间的最大子段和(tmax):三种情况取最大值// 情况1:跨越左右子区间的最大和(左子区间的后缀 + 右子区间的前缀)// 情况2:左子区间内部的最大子段和(le.tmax)// 情况3:右子区间内部的最大子段和(ri.tmax)u.tmax = max(le.rmax + ri.lmax, max(le.tmax, ri.tmax));
}

● 核心代码 pushup 示例解析
用一个具体例子 [-1, 3, -2, 6] 验证:
左子区间 le:[1,2],数值 [-1,3] → le.sum=2,le.lmax=2,le.rmax=3,le.tmax=3;
右子区间 ri:[3,4],数值 [-2,6] → ri.sum=4,ri.lmax=4,ri.rmax=6,ri.tmax=6;
合并成父区间 u:[1,4],数值 [-1,3,-2,6]:
u.sum = -1+3-2+6 = 6 = le.sum + ri.sum = 2 + 4 = 6(正确);
u.lmax = max(le.lmax,le.sum+ri.lmax) = max(2, 2+4) = 6(正确);
u.rmax = max(ri.rmax,ri.sum+le.rmax) = max(6, 4+3) = 7(正确);
u.tmax = max(le.rmax+ri.lmax,max(le.tmax,ri.tmax)) = max(3+4, max(3,6)) = max(7,6) = 7(正确,对应子段 [3, -2, 6])。

● pushup 里的 sum / lmax / rmax / tmax 的公式到底是怎么推导出来的?
其实这些公式不是凭空来的,而是基于「分治思想」和「子段的位置特征」推导的必然结果。
这些公式的本质是把 “父区间的问题” 拆解为 “子区间的子问题”,符合线段树 “分治 + 合并” 的核心思想 —— 只要子区间的信息足够,就能通过固定的逻辑合并出父区间的信息,这也是线段树能高效解决区间问题的关键。
(零)推导前的核心前提
我们把父区间记为 U,左子区间记为 L,右子区间记为 R(U = L + R,区间连续)。
所有子段的位置只有三种可能:
(1)完全落在 L 内;
(2)完全落在 R 内;
(3)跨越 L 和 R(一部分在 L 右部,一部分在 R 左部)。
所有公式的推导,都是围绕这三种位置特征展开的。
(一)推导 u.sum(父区间总和)
sum,表示整个区间的总和。
这个是最基础的,没有任何技巧:u.sum = le.sum + ri.sum
(二)推导 u.lmax(父区间的前缀最大和)
lmax,表示从区间左端点开始的各个子段的最大子段和(前缀最大和)。
以 U 的左端点开头的子段,只有两种可能:
(1)不跨区间:子段完全在 L 内 → 对应 le.lmax(L 的前缀最大和);
(2)跨区间:子段包含整个 L,再延伸到 R 的一部分 → 对应 le.sum + ri.lmax(L 的全部和 + R 的前缀最大和)。
要找最大值,就取这两种情况的较大值:u.lmax = max(le.lmax, le.sum + ri.lmax)
(三)推导 u.rmax(父区间的后缀最大和)
rmax,表示以区间右端点结束的各个子段的最大子段和(后缀最大和)。
以 U 的右端点结尾的子段,只有两种可能:
(1)不跨区间:子段完全在 R 内 → 对应 ri.rmax(R 的后缀最大和);
(2)跨区间:子段包含整个 R,再延伸到 L 的一部分 → 对应 ri.sum + le.rmax(R 的全部和 + L 的后缀最大和)。
要找最大值,就取这两种情况的较大值:u.rmax = max(ri.rmax, ri.sum + le.rmax)
(四)推导 u.tmax(父区间的最大子段和)
tmax,表示整个区间内各个子段的最大子段和。
根据开头的 “三种位置”,最大子段和的候选来源有三个:
(1)完全在 L 内:对应 le.tmax(L 的最大子段和);
(2)完全在 R 内:对应 ri.tmax(R 的最大子段和);
(3)跨越 L 和 R:这种子段一定是「L 的后缀最大和 + R 的前缀最大和」→ 对应 le.rmax + ri.lmax(因为跨区间的子段,左边要取 L 的后缀最大,右边要取 R 的前缀最大,才能凑出最大和)。
要找最大值,就取这三种情况的较大值:u.tmax = max(le.rmax + ri.lmax, max(le.tmax, ri.tmax))

【算法代码】

#include <bits/stdc++.h>
using namespace std;const int N=5e5+5;
int a[N];
int n,m;struct node {int le,ri;int tmax,lmax,rmax,sum;
} tr[N*4];void pushup(node &u,node &le,node &ri) {u.sum=le.sum+ri.sum;u.lmax=max(le.lmax,le.sum+ri.lmax);u.rmax=max(ri.rmax,ri.sum+le.rmax);u.tmax=max(le.rmax+ri.lmax,max(le.tmax,ri.tmax));
}void pushup(int u) {pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}void build(int u,int le,int ri) {if(le==ri) tr[u]= {le,ri,a[ri],a[ri],a[ri],a[ri]};else {tr[u]= {le,ri};int mid=le+ri>>1;build(u<<1,le,mid);build(u<<1|1,mid+1,ri);pushup(u);}
}void modify(int u,int p,int v) {if(tr[u].le==p && tr[u].ri==p) tr[u]= {p,p,v,v,v,v};else {int mid=tr[u].le+tr[u].ri>>1;if(p<=mid) modify(u<<1,p,v);else modify(u<<1|1,p,v);pushup(u);}
}node query(int u,int le,int ri) {if(tr[u].le>=le && tr[u].ri<=ri) return tr[u];int mid=tr[u].le+tr[u].ri>>1;if(ri<=mid) return query(u<<1,le,ri);else if(le>mid) return query(u<<1|1,le,ri);else {auto left=query(u<<1,le,ri);auto right=query(u<<1|1,le,ri);node t;pushup(t,left,right);return t;}
}int main() {cin>>n>>m;for(int i=1; i<=n; i++) cin>>a[i];build(1,1,n);int op,x,y;while(m--) {cin>>op>>x>>y;if(op==1) {if(x>y) swap(x,y);cout<<query(1,x,y).tmax<<endl;} else modify(1,x,y);}return 0;
}/*
in:
5 3
1
2
-3
4
5
1 2 3
2 2 -1
1 2 3out:
2
-1
*/





【参考文献】
https://www.acwing.com/solution/content/110854/
https://www.acwing.com/video/649/


 

http://www.jsqmd.com/news/294903/

相关文章:

  • 2026年水果冻库臭氧机优质品牌推荐榜
  • 关于今天cloudflare新添的验证
  • 【Django毕设全套源码+文档】基于Django的设计与实现(丰富项目+远程调试+讲解+定制)
  • 【Django毕设全套源码+文档】基于Python的人事管理系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • 【Django毕设全套源码+文档】基于Django的美食推荐系统设计与实现(丰富项目+远程调试+讲解+定制)
  • 【Django毕设全套源码+文档】基于Django的校园荣誉证书管理系统设计与实现(丰富项目+远程调试+讲解+定制)
  • 【Django毕设全套源码+文档】基于Python的校园个人闲置物品换购平台的设计与实现(丰富项目+远程调试+讲解+定制)
  • AI产品经理入门全攻略:与传统PM的7大差异+大模型学习路径,非常详细收藏我这一篇就够了
  • 【Django毕设全套源码+文档】基于Python的适老化(老年人)健康预警系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • 【计算机毕业设计案例】基于springboot的小型图书销售系统基于springboot的便民社区图书销售系统的设计与开发(程序+文档+讲解+定制)
  • Java毕设项目:基于springboot的便民社区图书销售系统的设计与开发(源码+文档,讲解、调试运行,定制等)
  • 新手进阶Python:办公看板集成可视化升级+精细化权限+定制报表导出
  • ### 技术文章大纲:C语言造轮子大赛
  • 【课程设计/毕业设计】基于springboot在线图书销售系统的设计与实现基于springboot的便民社区图书销售系统的设计与开发【附源码、数据库、万字文档】
  • 图数据库+大模型:GraphRAG如何解决大模型落地难题,让AI真正走进产业
  • 大模型开发必学:从零开始构建基于上下文工程的Agent后端系统【收藏学习】
  • LLM-RL训练框架全攻略:四大主流框架横向评测与选型指南
  • Java计算机毕设之基于springboot的便民社区图书销售系统的设计与开发springboot图书销售系统设计与实现(完整前后端代码+说明文档+LW,调试定制等)
  • 【毕业设计】基于springboot的便民社区图书销售系统的设计与开发(源码+文档+远程调试,全bao定制等)
  • 2026评价高的肛肠诊疗优质机构推荐
  • Node.js用require.resolve优化模块加载
  • 14: curl#6 - Could not resolve host: mirrorlist.centos.org; Unknown error
  • 2026年乐山品质跷脚牛肉品牌推荐榜
  • 网络包分析工具wireshark采用教程
  • 签到
  • 2026乐山优质跷脚牛肉店推荐榜:乐山跷脚牛肉本地人推荐/乐山跷脚牛肉非遗店/好吃的乐山跷脚牛肉店/推荐一下乐山跷脚牛肉/正宗的乐山跷脚牛肉/选择指南
  • python基于微信小程序的校园食堂订餐服务系统
  • 学术开题“黑科技”:书匠策AI如何让你的研究赢在起跑线?
  • 开题报告“救星”来了!书匠策AI带你玩转科研第一步
  • 论文开题“黑科技”:书匠策AI如何成为你的科研导航仪?