求解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. html公用头部和尾部

    这个方式比较简单,样式和js也有效果,还有object和iframe方式 效果图,可以看出公共的样式对于引入的文件也有效果,在加载完文件后js也是有效果的 index.html header.html ...

  2. Python开发GUI实战:图片转换素描画工具!

    奋斗没有终点 好好学习72变,因为将来 没有人能替你阻挡81难 . 生如蝼蚁,当有鸿鹄之志: 命如纸薄,应有不屈之心 . ​ 今天被这句话触动了,所以开篇分享给大家.鸡汤有毒,但有时大家却靠它激励自己 ...

  3. centos6和centos7的防火墙基本命令

    一.centos6: 1.firewall的基本启动/停止/重启命令 $查看防火墙状态: service iptables status (/etc/init.d/iptables status) $ ...

  4. body标签添加ontouchstart属性

    之前看别人的代码,发现他的body标签添加ontouchstart属性.即 <body ontouchstart> 上网查了一下原因,记录一下: 这个操作是进行手机端兼容处理的,防止伪类: ...

  5. 如何使用re模块进行测试用例的参数化

    import re import os from scripts.handle_mysql import HandleMysql from scripts.handle_config import H ...

  6. wp.editor.initialize 配置案例

    wp.editor.initialize ( 'EditorTextArea' , { tinymce: { wpautop: to true , theme: 'modern' , skin: 'l ...

  7. 在Asp.net Razor Pages/MVC程序中集成Blazor

    今天试了一下在Asp.net core Razor Pages/MVC程序中集成Blazor(Server-side),还是可以完美整合的,这里以Razor Pages为例(.net core 3.1 ...

  8. hello tensorflow,我的第一个tensorflow程序

    上代码: import tensorflow as tf if __name__=='__main__': g = tf.Graph() # add ops to the user created g ...

  9. mssql下调用dll

    1.新建类库,里面写入方法,类库里必须样静态,防止实例化 2.将dll存放到文件夹里 3.在sql中运行 EXEC sp_configure 'clr enabled' , '1'; --0代表不允许 ...

  10. HTML颜色名称大全

    所有浏览器支持的颜色名称,所有现代浏览器都支持以下140种颜色名称(单击颜色名称或十六进制值,以将颜色视为背景颜色以及不同的文本颜色): 有关HTML颜色的完整概述,请访问我们的颜色教程. 颜色名称 ...