P9058 [Ynoi2004] rpmtdq / P9678 [ICPC2022 Jinan R] Tree Distance

洛谷

人生中第一篇 Ynoi 题题解,好激动。

  • 给出一棵 n 个点的树,边有边权。

  • dist(u,v)u,v 两点简单路径上的边的权值之和。

  • q 次询问,每次询问给出 l,r,求 minli<jrdist(i,j)

  • n2×105q106

(i,j)(i<j) 为一个点对,若把 dist(i,j) 看作改点对的权值,则我们要求解一个二维偏序问题。

现在的问题就是点对太多了,一共有 O(n2) 个。不过,真的需要这么多点对吗?比如现在有两个点对 (x1,y1)(x2,y2) 满足 x1x2y2y1dist(x1,y1)dist(x2,y2),你发现若查询的区间包含了 (x1,y1),就一定包含了 (x2,y2),而且 (x2,y2) 的权值更小。因此 (x1,y1) 这个点对是没有用的。我们称 (x2,y2) 支配了 (x1,y1)

我们称一个点对为支配点对,当且仅当它不被其他点对支配

考虑找出一个集合 T 包含所有的支配点对且大小可接受。我们来找一下一个点对成为支配点对的必要条件。

考虑点分治,对于一个支配点对 (i,j),则一定存在一个分治重心 rt 满足 i,jrt 不同儿子的子树中。不妨钦定 dist(i,rt)dist(j,rt)。设 S 表示当前联通块中满足 dist(x,rt)dist(j,rt)xjx 构成的集合,i 一定是 S 中最大的 <j 的数(前驱)或最小的 >j 的数(后继)

为什么?考虑反证法,以前驱为例,设 j 的前驱为 pre,若 i<pre,根据 S 的定义可知 dist(i,rt),dist(pre,rt)dist(j,rt)

此时一定满足:

  • dist(i,pre)dist(i,rt)+dist(pre,rt)dist(i,rt)+dist(j,rt)=dist(i,j)

    dist(i,pre)dist(i,rt)+dist(pre,rt) 是因为相较于后者前者要减去根到 LCA 路径的边权和。

  • i<pre<j

你发现 (i,j)(i,pre) 支配了。后继的证法类似,此处不再赘述。

考虑这样一个过程,对于每一层点分治,对于每一个点维护集合 S,并找到前驱、后继并将该点对加入 T。那么任意一个支配点对 (i,j),点分治进行到使得它们在两棵不同子树中的联通块时,因为 i 一定是前驱或后继,那么对于 j 这个点找前驱、后继的时候,就把这个点对找到了。所以这样找到的 T 集合包含了所有支配点对。

并且,由于点分治只会进行 O(logn) 层,每一层每个点带来 O(1) 个点对,因此找到的总点对数量为 O(nlogn)

具体地,如何实现这个构造 T 的过程?对于每一个联通块的点分治,将所有点 u 按照编号升序排序。正着反着扫一遍,维护一个随着 u 递增 / 递减,dist(u,rt) 不降的单调栈。那么对于一个点 v,它就是被它出栈的那些点的前驱 / 后继。

我们已经得到了集合 T,那么拿 T 中的点对去做二维数点即可。考虑离线 + 倒序扫描 i 保证 li,用树状数组维护 jr 求前缀最值即可。至于 dist(i,j),用树剖 + LCA 求一下即可。

时间复杂度为 O(nlog2n+qlogn),空间复杂度为 O(nlogn+q)

提交记录 代码

posted @   lzyqwq  阅读(103)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 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】
点击右上角即可分享
微信分享提示