P3379 最近公共祖先模板

题目链接

顾名思义 就是求两个点的公共祖先

暴力做法就是先维护每个点的父亲 然后枚举

但显然这样的做法查询复杂度是O(n)的 就TLE了(


所以需要用倍增优化:

用f[i][j]表示第i个点 向上跳 2j 个父亲得到的点的编号


显然 有f[i][0] = fa[i] :

然后是递推式 不难看出f[i][j]可以看作是i先跳 2j1 格到f[i][j-1] 然后再跳 2j1 格 所以有:

至此 预处理完成 复杂度为O(nlogn)


那么如何查找 x 与 y 的最近公共祖先呢?

首先我们先将较低的那个跳到与另一个深度相同:

注意跳完后可能发生以下情况:

所以当 x 跳完与 y 重合 我们就直接输出:

然后 x 与 y 就能一起往上跳了

我们把 j 从大到小枚举 若 f[x][j] == f[y][j] 就说明跳过头了 :

所以 x 与 y 往上跳的条件即为 f[x][j] != f[y][j] :

当然 最后 x 与 y 会停在离最近公共祖先差一格的位置(因为再往上一格 f[x][j] 就等于 f[y][j] 没法跳)

所以此时输出 f[x][0] ( f[y][0] 一样的 写啥看心情 甚至我感觉其实写 fa[x] 都行 )

查询的复杂度为O(logn)


完整代码如下:



posted @   Steven24  阅读(53)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 一个适用于 .NET 的开源整洁架构项目模板
· API 风格选对了,文档写好了,项目就成功了一半!
· 【开源】C#上位机必备高效数据转换助手
· .NET 9.0 使用 Vulkan API 编写跨平台图形应用
· MyBatis中的 10 个宝藏技巧!
点击右上角即可分享
微信分享提示