求解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. js正则高级函数(replace,matchAll用法),实现正则替换(实测很有效)

    有这么一个文档,这是在PC端显示的效果,如果放在移动端,会发现字体大小是非常大的,那么现在想让这个字体在移动端能按照某个比例缩小,后台返回的数据格式是: <html> <head&g ...

  2. 分析Runtime的属性Property

    一.介绍 在OC中我们可以给任意的一个类以@property的格式声明属性,当然对于这个属性也会采用某一些属性关键字进行修饰,那么属性的真正的面目是啥样子的呢?其实,runtime源码中可以看到,pr ...

  3. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 1

    现在,如果你已经能熟练地使用MySQL客户端软件来操作数据库中的数据,就可以开始学习如何使用PHP来显示和修改数据库中的数据了.PHP提供了标准的函数来操作数据库.在PHP 5以上的版本中可以使用My ...

  4. IT兄弟连 Java语法教程 流程控制语句 控制循环结构1

    Java语言没有提供goto语句来控制程序的跳转,这种做法提高了程序流程控制的可读性,但降低了程序流程控制的灵活性.为了弥补这种不足,Java提供了continue和break来控制循环结构.除此之外 ...

  5. 前端笔记之React(七)redux-saga&Dva&路由

    一.redux-saga解决异步 redux-thunk 和 redux-saga 使用redux它们是必选的,二选一,它们两个都可以很好的实现一些复杂情况下redux,本质都是为了解决异步actio ...

  6. [03-2]VS2017 创建 ASP.NET Core Web 程序

    VS2017 创建 ASP.NET Core Web 程序 本文作者:梁桐铭- 微软最有价值专家(Microsoft MVP) 文章会随着版本进行更新,关注我获取最新版本 本文出自<从零开始学 ...

  7. 安装Keepalived namespaces.c:187: error: ‘SYS_setns’ undeclared (first use in this function)

    错误信息 namespaces.c: In function ‘setns’: namespaces.c:: error: ‘SYS_setns’ undeclared (first use in t ...

  8. C# recording audio based on audio in Console

    1. Install-package naudio -v 1.9.0 2. using NAudio.Wave; 3. public class NAudioHelper { public WaveI ...

  9. 仅支持基本增删改查的学生自制php操作mysql的工具类 DB.class.php (学生笔记)

    <?php class DB{ //主机地址 var $host; //用户名 var $username; //密码 var $password; //数据库名 var $dbname; // ...

  10. 虚拟机Centos6.7安装VMTools

    安装VMware Tools,设置共享文件夹 一.基本步骤 1.VMware Workstation菜单栏中,选择“虚拟机”,”安装VMware Tools...“.(注:此时下方可能会弹出“确保您已 ...