「Codechef」Children Trips

Description

你在一颗树上旅行

树由 $n$ 个点$n - 1$ 条边构成每条边的长度 $w$$1$$2$

你要从点 $u$ 沿着唯一的简单路径走到点 $v$但是你的体力有限所以一天之内最多只能走 $l$ 的距离一天结束时待在树的节点外是很危险的所以你必须在一天结束前到达某个节点并停下可以刚好到达即使你没有走到 $l$ 的距离

给定这棵树和 $q$ 个询问每个询问给出 $u,v,l$请求出至少需要多少天

数据范围 : $1 \leqslant n,q \leqslant 10^5, 1 \leqslant x,y,u,v \leqslant n,w \in \{1, 2\}, 2 \leqslant l \leqslant 2n.$

Tutorial

Lemma1: 一条路径正着走和倒着走答案是一样的

Proof1: 考虑将正着和倒着每天累计走的距离写下来容易发现正着走相当于一开始落后了至多 $1$ 的距离后面在不断追赶可以发现在走的过程中是存在单调性的所以正着走一定不可能超过倒着走但也不可能落后超过 $1$由于最后会走到相同的位置所以答案是一样的

有了上述引理我们就可以考虑分别计算 $u$$v$ 分别跳到 $\textrm{LCA}(u, v)$ 下面最高能跳到的点的答案$l_1, l_2$ 分别表示 $u$$v$ 剩下的距离最终答案即为 $u$$v$ 的答案之和加上 $\left\lceil\frac{l_1 + l_2}{l}\right\rceil$

考虑对询问根号分治分别处理 $l \leqslant \sqrt{n}$ 的询问和 $l > \sqrt{n}$ 的询问

  • 对于 $l > \sqrt{n}$ 的询问可以发现其跳的次数不超过 $\sqrt{n}$于是可以直接暴力跳用倍增维护一下即可
  • 对于 $l \leqslant \sqrt{n}$ 的询问可以预处理出从每个点 $u$ 开始此时的 $l = k$往上跳 $2 ^ i$ 天到的点 $f_{u, k, i}$倍增往上跳即可

时间复杂度 $\Theta(n \sqrt{n} \log n)$卡一卡常可以通过

考虑换一种思路我们给树上 $\sqrt{n}$ 个点打上标记称它们为特殊点那么如果标记打得足够均匀就可以使 $u, v \to \textrm{LCA}(u, v)$ 的路径上每隔 $\sqrt{n}$ 的距离经过一个特殊点且总共经过 $\sqrt{n}$ 个特殊点至于如何打标记可以记 $dis_u$ 表示 $u$ 到树上最远点的距离$B = \sqrt{n}$$u$ 为标记点当且仅当 $B | dis_u$

考虑预处理 $f_{u, k}$ 表示当 $l = k$$u$ 开始走一天到的点如果这个点超过了 $u$ 祖先中最深的特殊点那么就将 $f_{u, k}$ 设为该特殊点并且计算剩下了多少距离$g_{u, k}$ 表示当 $l = k$$u$ 开始走到 $u$ 祖先中最深的特殊点需要花费的天数

容易发现由于走到 $u$ 祖先中最深的特殊点最多 $2\sqrt{n}$ 的距离所以 $k$ 的取值范围为 $[0, 2\sqrt{n}]$预处理直接从上往下递推即可由于状态总数是 $n \sqrt{n}$所以预处理时间复杂度也是 $\Theta(n \sqrt{n})$至于如何使用这两个数组优化往上跳的过程则是简单的不作赘述

总时间复杂度 $\Theta(n \sqrt{n})$可以轻松通过此题