跳过并跳转到主要内容

倍增

倍增法(Binary Lifting),核心思想是利用二进制拆分,预处理出跳 2⁰、2¹、2²… 步的状态,把单次大步查询拆解成若干次预计算的小步跳转,将原本线性的时间复杂度优化到对数级别,常用于 LCA、RMQ、后缀数组等问题。

算法设计1分钟阅读
树上倍增(Binary Lifting)算法示意图,橙色箭头展示 1、2、4 步跳跃向上查找祖先的过程
树上倍增(Binary Lifting)算法示意图,橙色箭头展示 1、2、4 步跳跃向上查找祖先的过程

倍增法(Binary Lifting / Doubling Technique) 是一种在计算机科学与算法设计中非常经典且高效的思想。

它的核心核心逻辑非常简单:“成倍增长,跳跃前进”。通过利用 22 的幂次方(1,2,4,8,16…1, 2, 4, 8, 16 \dots),将原本需要逐位线性推导的 O(N)O(N) 复杂度,大幅降低到 O(log⁡N)O(\log N)。

在日常生活中,如果让你用尽可能少的硬币凑出某个金额,或者用最少的操作步数走完一段距离,指数级递增是最快速的缩小范围方式。

倍增法建立在一个基础数学事实之上:任何正整数都可以唯一地表示为二进制数(即若干个 2 的幂次方之和)。

  • 例如:走 13 步,可以拆解为 8+4+18 + 4 + 1(即二进制 1101)。
  • 我们不需要一步一步走 13 次,而是直接跳跃 8 步,再跳跃 4 步,最后跳跃 1 步,仅用 3 次跳跃 即可到达目的地。

倍增法在图论、动态规划以及高级数据结构中有非常广泛的应用,最典型的两大应用场景如下:

在树形结构中,求两个节点的最近公共祖先,如果朴素地让较深的节点一步步向上爬,效率会比较低(退化成链时为 O(N)O(N))。

  • 倍增做法: 预处理出每个节点向上跳 2k2^k 步所到达的祖先节点,定义 dp[u][k] 为节点 u 的第 2k2^k 个祖先。

  • 转移方程:

    dp[u][k]=dp[dp[u][k−1]][k−1]\text{dp}[u][k] = \text{dp}[\text{dp}[u][k-1]][k-1]

    即:“向上跳 2k2^k 步” 等价于 “先向上跳 2k−12^{k-1} 步,再从那个节点向上跳 2k−12^{k-1} 步”。

  • 查询阶段: 借助预处理好的数组,先把两个节点对齐到同一深度,然后利用二进制思想从大到小(如 220,219…202^{20}, 2^{19} \dots 2^0)尝试向上跳跃,即可在 O(log⁡N)O(\log N) 时间内锁定 LCA。

计算 ab(modm)a^b \pmod m 时,如果连乘 bb 次,复杂度是 O(b)O(b)。

  • 倍增做法: 利用 a2k=(ak)2a^{2k} = (a^k)^2,把指数 bb 进行二进制拆分。
  • 这样可以将原本需要执行 bb 次的乘法,缩减至约 log⁡2b\log_2 b 次操作。

  1. 查询极快: 单次查询复杂度从线性 O(N)O(N) 降至对数级 O(log⁡N)O(\log N)。
  2. 状态转移优雅: 利用二进制按位处理,代码实现逻辑通常非常清晰。

  1. 需要预处理空间: 需要存储 O(Nlog⁡N)O(N \log N) 规模的状态矩阵(如 dp[N][LOGN])。
  2. 通常要求状态可合并且静态: 如果原图结构或数据频繁发生动态修改,倍增数组的维护成本会比较高(此时通常需要结合树链剖分或 LCT 等更高级数据结构)。

© 2026 三七开 · 一方通行,只管向前。

旅途由 Astro 驱动 · 主题 Chirping Astro