比较简单的 O(n)-O(1) 树上 K 祖先
wangyanjing
·
·
算法·理论
一个比较简单的 O(n) - O(1) 的在线静态树上 K 祖先。
此算法需要保证:k < dep_{u},当然 k \ge dep_u 的点本来就不存在,在其他题用的时候可以判一下这个细节。
记 rt 为根,E_i 为欧拉序,令 f_i 表示从 E_i 往上跳 \text{lowbit}(i) 条边后的点,fst_u 表示 u 第一次在欧拉序中出现的位置。
如果 E_i 没有 \text{lowbit}(i) 级祖先,即 dep_{E_i} \le \text{lowbit}(i) 则令 f_i = rt。
这些显然可以 dfs O(n) 预处理。
对于一个查询 u 往上跳 k 步,令:
对于 k \le 1 的情况,直接返回 fa_u 或 u 即可,下面认为 k \ge 2,这说明 \{rt\} \cup son_{rt} 都不会成为 u。
令:p = 2^{\lfloor \log_2 k\rfloor -1},i = fst_u。
令:x = i \bmod (2p),w = i - x + p。
此时 |i - w| = |x - p|,由于 x \in [0,2p),所以 x - p \in [-p,p),所以 |x-p | \le p。
利用欧拉序的性质 dis(E_i,E_j) \le |i-j|。
::::success[证明 dis(E_i,E_j) \le |i-j|]
现在假定 i \le j,如果不是就交换 i,j 即可。
显然欧拉序相邻的点在树上相邻,所以有 dis(E_i,E_{i+1}) = 1。
所以存在一条路径:E_i \to E_{i+1} \to E_{i+2} ,\dots, \to E_j,因为所有的路径长度都 \ge 最短路,所以有一些式子:
dis(E_i,E_j) \le \sum_{k = \min(i,j)}^{\max(i,j)-1} dis(E_k,E_{k+1}) = |i-j|
::::
所以 dis(u,E_w) \le p,由于此时 \text{lowbit}(w) = p,令 t = f_w,c = \text{LCA}(u,E_w) 则:
我们可以考虑证一下 w 不会越界。
::::success[证明 w 不会越界]
首先,因为这是欧拉序,所以走到 E_i 至少需要 dep_{E_{i}} -1 步,然后走回根同理,所以:
dep_{E_i} \le i \\
2n-1 - i \ge dep_{E_i} - 1
其中 2n-1 是欧拉序的长度。
又有:2p \le k < dep_{E_i},所以从 i 往左或往右不超过 2p 都不越界。
| 而 p \ge 1,所以 2p-1 \ge p,所以 w 不会越界。 |
发现:t \ne rt。
这里需要用一下欧拉序的性质:dep_{E_i} \equiv i \pmod 2。
::::success[证明 dep_{E_i} \equiv i \pmod 2]
首先有:d_i = dep_{E_i} - dep_{E_{i-1}} \in \{1,-1\},令 dep_0 = 0。
我们考虑数学归纳,首先 E_1 = rt,dep_{rt} = 1,所以符合结论。
考虑若 dep_{E_i} \equiv i \pmod 2,我们看看对 i+1 是否成立。
容易发现:(dep_{E_i} -1 ) \bmod 2 = (dep_{E_i} + 2 -1) \bmod2 = (dep_{E_{i}}+1) \bmod 2。
所以:(i+1) \equiv (dep_{E_i}+1) \equiv (dep_{E_i} -1) \pmod 2。
所以:(i+1) \equiv (dep_{E_i} + d_{i+1})=dep_{E_{i+1}} \pmod 2。
证毕!
::::
::::success[证明 t \ne rt]
若 t = rt,则 dep_{E_w} \le p+1。
w = i -x + p =i - (i - \lfloor \frac{i}{2p} \rfloor 2p) + p = p(1 + 2\lfloor \frac{i}{2p} \rfloor)
所以:$dep_{E_w} \le p$,所以有:
$$
dep_u = dis(rt,u)+1 \le 1 +dis(u,E_w) + dis(E_w,rt) = dis(u,E_w) + dep_{E_w} \le 2p \le k
$$
又有 $k < dep_u$,但是我们证出来 $dep_u \le k$,所以根本没有这样的 $k$。
::::
所以 $dep_{E_w} > p$,所以:
$$
dis(u,E_w) = dep_u + dep_{E_w} - 2 dep_{c} \le p \\
dep_{E_w} - dep_{t} = p
$$
上下相减得:
$$
dep_{u} + dep_t - 2 dep_c \le 0 \\
\therefore dep_t - dep_c \le dep_c - dep_u \le 0
$$
因为 $t,c$ 都可以通过 $E_w$ 向上跳得到,所以:$t$ 是 $c$ 或 $c$ 的祖先,所以 $t$ 是 $u$ 的祖先!!
此时:$dis(t,u) \le dis(u,E_w) + dis(E_w,t) \le 2p \le k$,所以 $t$ 不会超过答案!
考虑长链剖分,我们发现 $t$ 所在的长链的包含的边数 $l$ 满足 $l\ge p$,因为至少能从 $t$ 往下走到 $E_w$。
又有:$k < 2^{\lfloor\log_2 k \rfloor +1}$,所以:$k < 4p \le 4l$,所以我们从 $t$ 再往上跳不超过 $4p \le 4l$ 步,即可得到答案。
所以我们对于每条长链,预处理:
- $up_{u,i}$ 表示从链顶 $u$ 往上跳 $i$ 条边的点,$i \in [0,4l_u)$,其中 $l_u$ 表示 $u$ 为链顶的这条长链包含的边数。
- $down_{u,i}$ 表示从链顶 $u$,沿长链往下走 $i$ 条边的点,显然 $i \in [0,l_u]$。
这样,我们直接查 $top_{t}$ 的 $up$ 或 $down$ 即可。
预处理 $up,down$ 显然是 $O(\sum l_u) = O(n)$,因为可以把贡献摊到点上,而一个点只属于一条长链。
所以我们做出来了 $O(n) - O(1)$ 的树上 K 祖先。
代码很好写,就不放了。
# AIGC
感谢 gpt 6 Astra 教会我这个做法。