P16435 [APIO 2026 中国赛区] 集宝

· · 题解

思路:

S_i 表示第 i 颗宝石的邻域集合。

对于一次询问,考虑依次维护当前所有可能的可达点的集合,初始是 S_l,要走到下一个点的邻域内,那么可达点的集合会变为 S_l \cap S_{l + 1},以此类推,最后可达点的集合是 S_l \cap S_{l + 1} \cap \cdots \cap S_r

显然这样是有问题的,如果中间某个时刻是空集了怎么办?即若走到一个点 k 使得 S_l \cap \cdots S_k \ne \emptyset, S_l \cap \cdots S_k \cap S_{k + 1} = \emptyset

容易发现,令 T = S_l \cap \cdots S_k,那么在收集第 k + 1 个宝石时,所有 T 中的节点在贪心往 S_{k + 1} 中移动后一定都会在落一个点上。

这是因为若干邻域交一定是联通块,这是显然的,而一个联通块都往一个点贪心的蠕动,最后肯定是全部都到这个点邻域边界的某个点处,简单分讨一下即可证明。

还有一个性质,在从 x 出发时,到达某个 T 的点走的一定是简单路径,考虑归纳证明:

所以你可以发现,对于一次询问,它一定是走一条简单路径,然后接下来一直从某个点开始跳跳跳。

那么这题的做法就呼之欲出了,设 f(x, l, r) 表示从 x 出发收集 l \sim r 宝石的最短路径。

对于每个 l,求最远的 k 使得 S_l \cap \cdots S_k \ne \emptyset,令 T = S_l \cap \cdots S_k,若 x \in T,那么 x 不用动;否则 x 动过,最后一定在 T 的边界上,且又是简单路径,于是可以分讨一下 xT 子树内或者外面,可以倍增跳或者是到达 T 中的根。

若现在选手在 p,容易求出其到 S_{k + 1} 后的点 p',那么我们要求的是 f(p, k + 1, r);可以看作是 f(1, 1, r) - f(1, 1, k + 1) + dis(p, p'),这是因为即使从 1 出发,收集 k + 1 时也一定在 p' 这个点,于是可以直接差分。

于是我们只需要求 f(1, 1, i),直接模拟一遍即可。

现在问题转化为求区间邻域交了,这个咋做?考虑比上面更强的结论,树上邻域交,不仅是一个联通块,还是一个树上邻域,其中心在其中间某个点或者某条边的中点取到。

为了方便处理,可以在边中间插入一个点,这样两个邻域合并后的邻域中心也在点上;发现这个性质后,求区间邻域交,就比较简单了,考虑用线段树维护,只需要支持快速合并两个邻域成新的邻域了(或者无交):

求最远的 k 使得区间邻域交非空可以直接在线段树上二分解决;这样常数有点大,可以考虑倒着走不删除指针做到 O(m \log n)

总时间复杂度为 O((m + q) \log n \log m);可能会被卡常,但是因为没有修改,可以直接上猫树,做到 O(m \log n \log m + q \log n)