Skip to content

模型Model

Level Ancestor 问题

施工中 · 内容逐步修订

Level ancestor problem · LA query · 层祖先问题

在静态根树中按目标深度或向上步数返回唯一祖先,并比较倍增的对数查询与线性空间常数查询方案。

形式陈述 ​

接口与参数约定 ​

给定含 n≥1 个节点的静态有根树,根的深度固定为 0。目标深度及步数均为整数。对节点 v 和目标深度 d,定义

LA(v,d)=v 在深度 d 的唯一祖先,0≤d≤depth(v).

等价的第 k 个祖先接口返回 LA(v,depth(v)−k),其中 0≤k≤depth(v);k=0 返回 v,k=depth(v) 返回根。页面以下用目标深度 d,避免把“深度”与“向上步数”混作同一参数。

树的唯一根路径保证答案存在且唯一。若 d>depth(v) 或 d<0,接口应返回 ⊥ 或拒绝查询,不能依赖数组越界偶然充当哨兵。

Binary Lifting 基线 ​

二进制倍增保存

up[j][v]=v 的第 2j 个祖先.

预处理与空间为 O(nlog⁡(n+1)),查询把 k=depth(v)−d 按二进制分解,用最坏 O(log⁡(n+1)) 次跳转到答案。这一路线简单,还能同步维护路径摘要,但不是静态 Level Ancestor 的最优空间—查询组合。

先把查询压成一次跳跃与一次索引 ​

先求每个节点到最深后代的边数 h(v),并让每个非叶节点选一个最高的孩子继续路径。这些不相交的最长向下路径覆盖全部节点。每条原路径有 L 个节点,就在其顶部再复制至多 L 个祖先,遇根停止,形成 ladder;全部扩展表的长度至多 2n,构造只需 O(n) 时间。

节点 v 所属的原路径会一直走到它的最深后代,所以其 ladder 在根以下至少容纳 h(v) 步向上距离。对查询距离 k=depth(v)−d>0,取 j=⌊log2⁡k⌋,先跳到 u=ancestor(v,2j)。由于 v 是 u 的一个距离 2j 的后代,有 h(u)≥2j;剩余距离 k−2j<2j,因此答案落在 u 的扩展 ladder 内,可按深度直接索引。k=0 则立即返回 v。

若每个节点都保存全部跳指针,这个办法的查询已经是 O(1),但预处理和空间仍是 O(nlog⁡(n+1))。线性大小的 ladder 并没有消除那些跳指针。

用宏节点和微树把跳指针压到线性 ​

以下在字长 w=Ω(log⁡(n+1))、支持常数时间字访问的Word-RAM中分析。小规模树可直接制表;其余取 b=⌊(log2⁡n)/4⌋。把“子树至少有 b 个节点、每个孩子的子树都少于 b 个节点”的节点标为跳节点。它们的子树两两不交,因此最多有 n/b=O(n/log⁡n) 个。

仅对跳节点保存全部有效二次幂祖先;距离超过其深度时使用无祖先哨兵。构建时不需要先给所有其他节点建倍增表:知道距离 2j−1 的祖先 u 后,h(u)≥2j−1,可直接在 u 的 ladder 内再向上走 2j−1 步,得到下一个跳指针。每个跳节点花 O(log⁡n),总计 O(n)。

所有跳节点及其祖先称为宏节点,组成一棵连通宏树。一次遍历给每个宏节点 v 指定一个跳节点后代 w。对 d≤depth(v),有 LA(v,d)=LA(w,d),故使用 w 的一次跳跃和 ladder 索引即可在常数时间回答。

删除宏节点后的每个连通分量是少于 b 个节点的微树:若某分量根的子树至少有 b 个节点,其中就会包含一个最深的跳节点,与分量不含宏节点矛盾。固定孩子次序,一棵微树可用 DFS 上下行的 2(b−1) 位以内编码描述,所有形状至多 O(4b)=O(n) 种。对每种形状预计算“本地 DFS 节点编号、目标本地深度”的全部答案,共需

O(4bb2)=O(nlog2⁡n)=O(n)

时间和字空间。每棵实际微树只保存形状编码、根深度,以及本地编号到实际节点的数组,总共 O(n)。

查询若仍在原微树内,就查该形状表并还原节点;目标在微树之外时,直接转到微树根的父节点,再使用宏节点算法。最高置位也可由长度 n 的共享表在 O(n) 预处理后常数查询。由此得到完整的

O(n) 预处理,O(n) 字空间,O(1) 最坏查询.

微树形状表、跳节点表和 ladder 各有单独的线性预算;它们共同支撑这个静态界。

直觉

倍增把向上距离拆成二进制跳跃,ladder 方案则先用最高位跳到一条足够长的祖先链,再按深度直接索引剩余距离。后者利用长路径分解与有限复制把所有梯子总长控制在线性范围,从而以更细预处理换掉查询中的对数次跳转。

目标已在起点扩展 ladder 内的特例

图右侧是原路径 x−y 扩展成的 L2=(a,b,x,y),目标 a 已在其中,可直接索引;箭头把距离三演示为 2+1。它没有画出一般证明所用的切换:一般查询先跳到 u,再查 u 所属原路径的 ladder。本例若按一般步骤跳到 b,该表来自 L1=(r,a,b,c,d),其中同样能找到 a。

例子与边界

可追踪真例 ​

设根路径为 r−a−b−c−d,另有分支 b−x−y。深度依次为 0,1,2,3,4,且 depth(x)=3,depth(y)=4。

LA(y,1)=a,LA(y,2)=b,LA(d,3)=c.

第 3 个祖先查询 ancestor(y,3) 与 LA(y,1) 是同一答案;若把参数 3 错当成目标深度,就会返回 x,这正是两种 API 混用的典型错误。

推论与应用

与 LCA、动态树的区分 ​

最近公共祖先输入两个节点并寻找最深公共祖先;Level Ancestor 输入一个节点和一个深度。LCA 算法可以调用祖先跳跃作为子程序,Level Ancestor 也能帮助对齐深度,但两个问题的接口和最优预处理并不相同。

若树发生 link、cut 或换根,深度和 ladder 可能整体改变,静态线性预处理立即失效。动态版本应进入动态森林问题并分别报告更新、查询及换根成本,不能沿用本页 O(1) 查询而不计维护。

简洁树表示还可用平衡括号与 rank/select 支持祖先导航;其重点是 bit 空间,而非把指针树的 O(n) words 与 2n+o(n) bits 写成同一空间界。

参考资料
  • Michael A. Bender and Martín Farach-Colton, “The Level Ancestor Problem Simplified”, LATIN 2002 版本,§3.3–3.4 与 §4:ladder、跳节点及宏微树证明;期刊版发表于 Theoretical Computer Science 321(1), 2004。
  • Omer Berkman and Uzi Vishkin, “Finding Level-Ancestors in Trees,” Journal of Computer and System Sciences 48(2), 1994.
  • Paul F. Dietz, “Finding Level-Ancestors in Dynamic Trees,” WADS, 1991, for the dynamic contrast.
关系图谱5 个相邻概念 · 3 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
类型化关系