洛谷
人生中第一篇 Ynoi 题题解,好激动。
-
给出一棵 个点的树,边有边权。
-
记 为 两点简单路径上的边的权值之和。
-
有 次询问,每次询问给出 ,求 。
-
,。
称 为一个点对,若把 看作改点对的权值,则我们要求解一个二维偏序问题。
现在的问题就是点对太多了,一共有 个。不过,真的需要这么多点对吗?比如现在有两个点对 和 满足 且 ,你发现若查询的区间包含了 ,就一定包含了 ,而且 的权值更小。因此 这个点对是没有用的。我们称 支配了 。
我们称一个点对为支配点对,当且仅当它不被其他点对支配。
考虑找出一个集合 包含所有的支配点对且大小可接受。我们来找一下一个点对成为支配点对的必要条件。
考虑点分治,对于一个支配点对 ,则一定存在一个分治重心 满足 在 不同儿子的子树中。不妨钦定 。设 表示当前联通块中满足 且 的 构成的集合,则 一定是 中最大的 的数(前驱)或最小的 的数(后继)。
为什么?考虑反证法,以前驱为例,设 的前驱为 ,若 ,根据 的定义可知 。
此时一定满足:
-
。
是因为相较于后者前者要减去根到 路径的边权和。
-
。
你发现 被 支配了。后继的证法类似,此处不再赘述。
考虑这样一个过程,对于每一层点分治,对于每一个点维护集合 ,并找到前驱、后继并将该点对加入 。那么任意一个支配点对 ,点分治进行到使得它们在两棵不同子树中的联通块时,因为 一定是前驱或后继,那么对于 这个点找前驱、后继的时候,就把这个点对找到了。所以这样找到的 集合包含了所有支配点对。
并且,由于点分治只会进行 层,每一层每个点带来 个点对,因此找到的总点对数量为 个。
具体地,如何实现这个构造 的过程?对于每一个联通块的点分治,将所有点 按照编号升序排序。正着反着扫一遍,维护一个随着 递增 / 递减, 不降的单调栈。那么对于一个点 ,它就是被它出栈的那些点的前驱 / 后继。
我们已经得到了集合 ,那么拿 中的点对去做二维数点即可。考虑离线 + 倒序扫描 保证 ,用树状数组维护 求前缀最值即可。至于 ,用树剖 + 求一下即可。
时间复杂度为 ,空间复杂度为 。
提交记录 代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】