1. LCA 的倍增(binary lifting)算法中 up[k][v] 表如何构建,为什么查询时从大到小跳步,复杂度 O(log n)?
LCA 的倍增(binary lifting)算法中 up[k][v] 表如何构建?为什么查询时要从大到小跳步?总复杂度为何是 O(log n)?
- 倍增表 up[k][v] 的递推定义与构建过程
- 查询时"从大到小枚举 + 不越界才跳"的贪心正确性
- 预处理与单次查询的复杂度分析
倍增表 up[k][v] 表示节点 v 向上跳 2^k 步到达的祖先,构建时令 up[0][v]=parent[v],并递推 up[k][v]=up[k-1][up[k-1][v]],即"2^k 级祖先 = 2^(k-1) 级祖先再跳 2^(k-1) 步",预处理复杂度 O(n log n)。查询 LCA(u,v) 分两步:先用二进制位分解把深度较大的节点跳到与另一个节点同深度,再从 k=⌊log n⌋ 向 0 从大到小枚举,只要 up[k][u]≠up[k][v] 就同时上跳,最后返回二者的父节点,单次查询 O(log n)。
从大到小跳的原因是二进制分解的贪心正确性:跳升量必须按 2 的幂从高到低组合,等价于对"深度差"做二进制分解;更重要的是以 up[k][u]≠up[k][v] 作为判据,若二者相等说明 2^k 步已经到达 LCA 之上或恰为共同祖先,此时跳过去会越过 LCA,必须减小步长试探,最终必然停在 LCA 正下方,返回父节点即答案。
核心是"一步代价 O(1)、步长按 2 的幂递减"的倍增思想,与二分求第 k 级祖先的二进制分解一脉相承;"从大到小 + 不越界才跳"保证每一步决策在已定高位的基础上最优,是正确性的关键,面试时需强调不能从小到大跳。