求解LCA问题的几种方式

这篇随笔讲解图论中LCA问题(最近公共祖先)的几种求解方式及实现方法。LCA问题属于高级图论,所以希望读者学习过初级图论,知道图的一些基本知识,并懂得深搜算法的实现方式。这样理解本篇博客将会快捷、舒适。

知识准备

理解LCA问题,理解节点深度是至关重要的,大家可以画一棵树。在一棵树中,所有的节点都有一个深度。根节点的深度是1,其他节点的深度可以用深搜遍历树来处理出来。这样,我们就可以通过深度数组来实现解决LCA问题的算法。

朴素LCA算法

朴素LCA算法的实现过程大约是这样:对于询问的两个点\(x,y\),先判断两个点谁更深一些,然后把更深的点顺着它的父节点一步步往上提升,直到和\(y\)点的深度相等为止。然后同时提升\(x,y\)两点,直到这两个点变成同一个点,这时的那个点就是我们要求的LCA。

根据这个算法实现的特点,我们叫他“爬一爬”算法。这种算法极容易理解,但是奇慢无比。所以我们就不给代码了。

倍增LCA算法

刚刚提到的LCA朴素算法比较好理解,但是奇慢无比。所以我们推出了更高级一点的方法:倍增LCA。倍增思想其实是非常好用的一种优化思想,在算法优化中有很多使用实例。比如RMQ问题的暴力方法用倍增优化之后就变成了ST表(ST算法),比如LCA的爬一爬算法用倍增优化之后就变成了倍增LCA算法。

所谓倍增LCA,其实很好理解,就是原来的朴素算法是一个一个爬,我们现在变成一次爬\(2^k\)个,这样就会大大优化复杂度。

实现的步骤并没有任何变化:都是先爬比较小的那个,后一起爬。但是这个时候我们就要处理一个二维数组f。\(f[x][k]\)表示\(x\)的第\(2^k\)辈的祖先是谁。这样,我们就可以得出一个递推式:

\[f[x][k]=f[f[x][k-1]][k-1]
\]

需要说明的是,这里需要提前处理出f数组和deep数组,对于这种操作,我们可以在树上进行深搜来实现。

模板如下:

void dfs(int x,int f)
{
deep[x]=deep[f]+1;
fa[x][0]=f;
for(int i=1;(1<<i)<=deep[x];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)
continue;
dfs(y,x);
}
}

应该是很好理解的:\(x\)的第\(2^k\)辈的祖先就等于\(x\)的第\(2^{k-1}\)辈的祖先的第\(2^{k-1}\)辈的祖先。

(其实这是个动态规划的过程)

剩下的就是一些细节问题。请大家多多注意,以后求LCA问题的时候根据不同的题目要求,就改这个模板即可。

代码:

int lca(int x,int y)
{
int ret;
if(deep[x]<deep[y])
swap(x,y);
for(int i=20;i>=0;i--)
if(deep[fa[x][i]]>=deep[y])
x=fa[x][i];
if(x==y)
return y;
for(int i=20;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
else
ret=fa[x][i];
}
return ret;
}

求解LCA问题的几种方式的更多相关文章

  1. [C++]四种方式求解最大子序列求和问题

    问题 给定整数: A1,A2,-,An,求∑jk=iAk 的最大值(为方便起见,假设全部的整数均为负数,则最大子序列和为0) 比如 对于输入:-2,11,-4,13,-5,-2,答案为20,即从A2到 ...

  2. Codeforces Round #466 (Div. 2) B. Our Tanya is Crying Out Loud[将n变为1,有两种方式,求最小花费/贪心]

    B. Our Tanya is Crying Out Loud time limit per test 1 second memory limit per test 256 megabytes inp ...

  3. PyODPS DataFrame 处理笛卡尔积的几种方式

    PyODPS 提供了 DataFrame API 来用类似 pandas 的接口进行大规模数据分析以及预处理,本文主要介绍如何使用 PyODPS 执行笛卡尔积的操作. 笛卡尔积最常出现的场景是两两之间 ...

  4. Struts2实现ajax的两种方式

    基于Struts2框架下实现Ajax有两种方式,第一种是原声的方式,另外一种是struts2自带的一个插件. js部分调用方式是一样的: JS代码: function testAjax() { var ...

  5. Spark读写Hbase的二种方式对比

    作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 一.传统方式 这种方式就是常用的TableInputFormat和TableOutputForm ...

  6. Android中访问sdcard路径的几种方式

    以前的Android(4.1之前的版本)中,SDcard路径通过"/sdcard"或者"/mnt/sdcard"来表示,而在JellyBean(安卓4.1)系统 ...

  7. C#执行异步操作的几种方式比较和总结

    C#执行异步操作的几种方式比较和总结 0x00 引言 之前写程序的时候在遇到一些比较花时间的操作例如HTTP请求时,总是会new一个Thread处理.对XxxxxAsync()之类的方法也没去了解过, ...

  8. Windows10-UWP中设备序列显示不同XAML的三种方式[3]

    阅读目录: 概述 DeviceFamily-Type文件夹 DeviceFamily-Type扩展 InitializeComponent重载 结论 概述 Windows10-UWP(Universa ...

  9. CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking)

    CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking) 我在(Modern OpenGL用Shader拾取 ...

随机推荐

  1. Day5- Python基础5 模块导入、time、datetime、random、os、sys、hashlib、json&pickle

    本节目录: 1.模块的分类 2.模块的导入 3.time模块 4.datetime模块 5.random 6.os模块 7.sys模块 8.hashlib 9.json&pickle 一.模块 ...

  2. Redis思维导图

    Redis基本数据结构 1.String 1.1 数据结构 long len byte数组长度 long free 可用数组长度 char buff[] 数据内容 1.2 命令 键值:设置值通过字符串 ...

  3. Educational Codeforces Round 76 (Rated for Div. 2) B. Magic Stick 水题

    B. Magic Stick Recently Petya walked in the forest and found a magic stick. Since Petya really likes ...

  4. Python程序中的进程操作-进程池(multiprocess.Pool)

    目录 一.进程池 二.概念介绍--multiprocess.Pool 三.参数用法 四.主要方法 五.其他方法(了解) 六.代码实例--multiprocess.Pool 6.1 同步 6.2 异步 ...

  5. #3146. 「APIO 2019」路灯

    #3146. 「APIO 2019」路灯 题目描述 一辆自动驾驶的出租车正在 Innopolis 的街道上行驶.该街道上有 \(n + 1\) 个停车站点,它们将街道划分成了 \(n\) 条路段.每一 ...

  6. Java中Array与ArrayList的10个区别

    Array和ArrayList都是Java中两个重要的数据结构,在Java程序中经常使用.并且ArrayList在内部由Array支持,了解Java中的Array和ArrayList之间的差异对于成为 ...

  7. JDBC释放数据库连接

    try(){}写法会自动关闭连接 String sql = "select password from user where name = ?"; try(Connection c ...

  8. mosquitto配置文件

    #配置文件为mosquitto #参见mosquitto.conf(5)了解更多信息. #显示默认值,取消注释以更改. #使用#字符来表示注释,但只有当它是 #第一个字符就行了. #========= ...

  9. 用ASP.NET Core构建可检测的高可用服务--学习笔记

    摘要 随着现代化微服务架构的发展,系统故障的定位与快速恢复面临着诸多挑战,构建可检测的服务,帮助线上保障团队时刻掌控应用的运行状况越来越重要.本次分享会讲解如何让 ASP .NET Core 应用与现 ...

  10. Visual Studio 基础设置

    重置开发环境 菜单栏中选择“工具”/“导入和导出设置”/“重置所有设置” 设置行号 菜单栏中选择“工具”/“选项”/“文本编辑器”/“行号” 全屏显示 菜单栏中选择“视图”/“全屏显示” 为程序设置版 ...