求解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. AcWing 799. 最长连续不重复子序列

    网址  https://www.acwing.com/solution/AcWing/content/2069/ 题目描述给定一个长度为n的整数序列,请找出最长的不包含重复数字的连续子序列,输出它的长 ...

  2. Python参数类型以及实现isOdd函数,isNum函数,multi函数,isPrime函数

    Python参数类型以及实现isOdd函数,isNum函数,multi函数,isPrime函数 一.Python参数类型 形参:定义函数时的参数变量. 实参:调用函数时使用的参数变量. 参数传递的过程 ...

  3. matlab练习程序(BRIEF描述子)

    BRIEF特征全称:Binary Robust Independent Elementary Features.是一种能够快速计算图像特征描述符的方法,同样能够降低特征匹配的时间. 算法计算步骤如下: ...

  4. Codeforces Round #597 (Div. 2) F. Daniel and Spring Cleaning 数位dp

    F. Daniel and Spring Cleaning While doing some spring cleaning, Daniel found an old calculator that ...

  5. Java字符串面试问答

    字符串是使用最广泛的Java的类之一.在这里,我列出了一些重要的Java的字符串面试问答. 这将有助于您全面了解String并解决面试中与String有关的任何问题. Java基础面试问题 Java中 ...

  6. electron应用生成exe程序并打包过程记录

    1.写好应用程序后,安装 electron-packager 在 package.json 文件中加入配置项目 "scripts": { "build": &q ...

  7. struts2文件上传报错

    说明上传的文件为空,检查上传文件名

  8. jQuery 源码分析(十四) 数据操作模块 类样式操作 详解

    jQuery的属性操作模块总共有4个部分,本篇说一下第3个部分:类样式操作部分,用于修改DOM元素的class特性的,对于类样式操作来说,jQuery并没有定义静态方法,而只定义了实例方法,如下: a ...

  9. Vant ui

    轻量.可靠的移动端 Vue 组件库 https://youzan.github.io/vant/#/zh-CN/intro postcss-pxtorem vue:将px转化为rem,适配移动端van ...

  10. spring cloud 项目创建过程

    在使用spring cloud 项目创建微服务项目时,遇到过很多坑,现在我将整理如下: 条件:Idea 开发工具 maven 项目 1. 创建一个空的mvn项目. 2. 创建完了就添加Module,首 ...