求解LCA问题的几种方式
求解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数组和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问题的几种方式的更多相关文章
- [C++]四种方式求解最大子序列求和问题
问题 给定整数: A1,A2,-,An,求∑jk=iAk 的最大值(为方便起见,假设全部的整数均为负数,则最大子序列和为0) 比如 对于输入:-2,11,-4,13,-5,-2,答案为20,即从A2到 ...
- 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 ...
- PyODPS DataFrame 处理笛卡尔积的几种方式
PyODPS 提供了 DataFrame API 来用类似 pandas 的接口进行大规模数据分析以及预处理,本文主要介绍如何使用 PyODPS 执行笛卡尔积的操作. 笛卡尔积最常出现的场景是两两之间 ...
- Struts2实现ajax的两种方式
基于Struts2框架下实现Ajax有两种方式,第一种是原声的方式,另外一种是struts2自带的一个插件. js部分调用方式是一样的: JS代码: function testAjax() { var ...
- Spark读写Hbase的二种方式对比
作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 一.传统方式 这种方式就是常用的TableInputFormat和TableOutputForm ...
- Android中访问sdcard路径的几种方式
以前的Android(4.1之前的版本)中,SDcard路径通过"/sdcard"或者"/mnt/sdcard"来表示,而在JellyBean(安卓4.1)系统 ...
- C#执行异步操作的几种方式比较和总结
C#执行异步操作的几种方式比较和总结 0x00 引言 之前写程序的时候在遇到一些比较花时间的操作例如HTTP请求时,总是会new一个Thread处理.对XxxxxAsync()之类的方法也没去了解过, ...
- Windows10-UWP中设备序列显示不同XAML的三种方式[3]
阅读目录: 概述 DeviceFamily-Type文件夹 DeviceFamily-Type扩展 InitializeComponent重载 结论 概述 Windows10-UWP(Universa ...
- CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking)
CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking) 我在(Modern OpenGL用Shader拾取 ...
随机推荐
- C语言快速入门一:win10系统环境搭建
0.搭建环境:WIN10 64位 1.下载minGW.zip编译器 2.解决上述文件,配置环境变量 3.配置变成后验证:打开cmd命令行,输入gcc -v 提示以下内容,说明编译器安装成功 D:\mm ...
- acwing 848 有向图的拓扑序列
地址 https://www.acwing.com/problem/content/description/850/ 题目描述给定一个n个点m条边的有向图,图中可能存在重边和自环. 请输出任意一个该有 ...
- MVC、MTV、FBV、CBV、母版和继承:
cookie session cookie的定义: 保存在浏览器上的一组组键值对 (请求头) 为什么要有? http协议是无状态,每次的请求之间是相互独立的,没有办法保存状态. Django中操作co ...
- java之API初识
API概念 API(Application Programming Interface),应用程序编程接口.JavaAPI是一本程序员的字典 ,是JDK中提供给 我们使用的类的说明文档.这些类将底层的 ...
- CometOJ10C 鱼跃龙门
题目链接 problem 实际上就是对于给定的\(n\)求一个最小的\(x\)满足\(\frac{x(x+1)}{2}=kn(k\in N^*)\). solution 对上面的式子稍微变形可得\(x ...
- matlab练习程序(图像投影到点云)
最近接触点云比较多,如果把图像投影到点云应该挺有意思. 首先需要载入图像,然后做个球或其他什么形状的点云,这里可以参考球坐标公式. 最后通过pcshow将像素输出到点云上即可. 原图: 投影后的点云: ...
- Python 相对路径和绝对路径--python实战(九)
一 背景信息 最近在运行python程序的过程中,无意遇到了这个一个问题,在同事那边一直执行ok的程序,到我这里怎么都有个错误,当初报的错误是这样的: FileNotFoundError: [Errn ...
- SQLServer临时库文件太大,迁移tempdb数据库
问题描述: 最近公司这边tempdb库文件很大,几百GB的节奏 不过安装数据库的时候,tempdb最好不要放在C盘是放在D盘其他数据盘的 如果没有放在其他盘符下面,就需要做迁移了 解决方法: 如果te ...
- java自定义equals函数和hashCode函数
所有类都继承自Object类,他所有的非final方法:equals,hashCode, toString, clone 和 finalize,它们都有通用约定. 我们在覆盖这些方法的时候需要遵循这些 ...
- JXL工具包对Excle文件操作
1.简介: XL - JXL(Java Excel API)是一个用来动态读写 Excel 文件的开源框架,利用它可以 在任何支持 Java 的操作系统上动态读写 Excel 文件. 2.开发步骤 1 ...