LCA(最近公共祖先)算法
参考博客:https://blog.csdn.net/my_sunshine26/article/details/72717112
首先看一下定义,来自于百度百科
LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。

注意:这里某个节点本身也是它的祖先节点。
求最近公共祖先的算法:
1、暴力:每次查询的时间复杂度为O(N)
2、Tarjan(离线)算法:在一次遍历中把所有查询解决,预处理时间复杂度O(nlogn),每次查询时间复杂度O(1),总时间复杂度是O(nlogn+q)
3、倍增算法:利用二分两个节点同时往上走,直到相遇,预处理时间复杂度O(nlogn),每次查询时间复杂度O(logn)
Tarjan(离线)算法
一.Tarjan算法大致实现过程
- 先选择一个节点u为根节点,从根节点开始搜索。(标记u已访问过)
- 遍历该点u的所有儿子节点v,并标记v已访问过。
- 若v还有儿子节点,对v重复ii操作,否则进入下一操作。
- 把v合并到u上(并查集)。
- 把当前的点设为u,遍历与u有询问关系的节点v。
- 如果v在之前已经被访问过,那么u和v的最近公共祖先就是v通过并查集合并后的父亲节点(注意是合并后),即当前的find(v)。
二.Tarjan算法的伪代码
Tarjan(u) //根节点u
{
for each(u,v)
{
Tarjan(v); //v还有儿子节点
join(u,v); //把v合并到u上
vis[v]=; //访问标记
}
for each(u,v) //遍历与u有询问关系的节点v
{
if(vis[v])
{
ans=find(v);
}
}
}
三.Tarjan算法的代码
void Tarjan(int u)
{
vis[u]=;
for(int i=;i<mp[u].size();i++)
{
int v=mp[u][i];
if(vis[v]==)
{
Tarjan(v);
join(u,v);
}
}
for(int i=;i<mp2[u].size();i++)//利用mp2集合来存储查询关系
{
int v=mp2[u][i];
if(vis[v]==)
{
lca[u][v]=find(v);
}
}
}
倍增算法
一、算法铺垫
首先让u和v中较深的一个往上走|depth(u)-depth(v)|步,然后再一起一步步往上走,直到走到同一个节点,就可以在O(depth(u)+depth(v))的时间内求出LCA。
关键在于如何优化向上查找的过程
二.倍增算法的实现过程
分析刚才的算法,两个节点到达同一节点后,不论怎么向上走,达到的显然还是同一节点。利用这一点,我们就能够利用二分搜索求出到达最近公共祖先的最小步数了。
首先我们要进行预处理。对于任意的节点,可以通过fa2[v]=fa[fa[v]]得到其向上走2步到达的顶点,再利用这个信息,又可以通过fa4[v]=fa2[fa2[v]]得到其向上走4步所到的顶点。以此类推,我们可以得到其向上走2^k步所到的顶点fa[v][k],预处理的时间点复杂度为O(nlogn)。
void init()
{
lg[]=;
for(int i=;i<=n;i++)
lg[i]=lg[i-]+(<<(lg[i-]+)==i);//用来求log2(n)
}
void dfs(int f,int fath)
{
deepth[f]=deepth[fath]+;
fa[f][]=fath;
for(int i=;(<<i)<=deepth[f];i++)
fa[f][i]=fa[fa[f][i-]][i-];
for(int i=;i<mp[f].size();i++)
if(mp[f][i]!=fath)
dfs(mp[f][i],f);
}
int lca(int x,int y)
{
if(deepth[x]<deepth[y])
swap(x,y);
while(deepth[x]>deepth[y])
x=fa[x][lg[deepth[x]-deepth[y]]];
if(x==y)
return x;
for(ll k=lg[deepth[x]];k>=;k--)
if(fa[x][k]!=fa[y][k])
x=fa[x][k], y=fa[y][k];
return fa[x][];
}
LCA(最近公共祖先)算法的更多相关文章
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)
Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...
- LCA近期公共祖先
LCA近期公共祖先 该分析转之:http://kmplayer.iteye.com/blog/604518 1,并查集+dfs 对整个树进行深度优先遍历.并在遍历的过程中不断地把一些眼下可能查询到的而 ...
- LCA 近期公共祖先 小结
LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...
- lca 最近公共祖先
http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...
- LCA(最近公共祖先)模板
Tarjan版本 /* gyt Live up to every day */ #pragma comment(linker,"/STACK:1024000000,1024000000&qu ...
- CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )
CodeVs.1036 商务旅行 ( LCA 最近公共祖先 ) 题意分析 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从 ...
- LCA最近公共祖先 ST+RMQ在线算法
对于一类题目,是一棵树或者森林,有多次查询,求2点间的距离,可以用LCA来解决. 这一类的问题有2中解决方法.第一种就是tarjan的离线算法,还有一中是基于ST算法的在线算法.复杂度都是O( ...
- LCA(最近公共祖先)之倍增算法
概述 对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 如图,3和5的最近公共祖先是1,5和2的最近公共祖先是4 在本篇中我们先介 ...
- LCA最近公共祖先(Tarjan离线算法)
这篇博客对Tarjan算法的原理和过程模拟的很详细. 转载大佬的博客https://www.cnblogs.com/JVxie/p/4854719.html 第二次更新,之前转载的博客虽然胜在详细,但 ...
- 最近公共祖先算法LCA笔记(树上倍增法)
Update: 2019.7.15更新 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了. 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了 ...
随机推荐
- SparkSQL执行时参数优化
近期接手了不少大数据表任务调度补数据的工作,补数时发现资源消耗异常的大且运行速度却不怎么给力. 发现根本原因在于sparkSQL配置有诸多问题,解决后总结出来就当抛砖引玉了. 具体现象 内存CPU比例 ...
- C语言学习记录_2019.02.12
"学计算机一定要有一个非常强大的心理状态,计算机不是黑魔法,都是人想出来的,别人能够想的出来,那么,总有一天,我也能够想的出来." 指针类型的变量就是保存地址的变量. int* p ...
- msserver的update or insert语句
方案1:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; BEGIN TRANSACTION; IF EXISTS (SELECT 1 FROM dbo.ta ...
- VS2015 安装XAN
How to install XNA in Visual Studio 2015 (Preview) How can I install the templates and the the frame ...
- 如何查看PostgreSQL的checkpoint 活动
磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面:PostgreSQL基础知识与基本操作索引页 回到顶级页面:PostgreSQL索引页 作者:高健@博客园 luckyjackgao@g ...
- python基础学习2-easygui框架编程
#!/usr/bin/env python # -*- coding:utf-8 -*- import easygui as g #导入方式一 #导入方式2 #from easygui import ...
- 【转载】COM 组件设计与应用(十三)——事件和通知(VC6.0)
原文:http://vckbase.com/index.php/wv/1243.html 一.前言 我的 COM 组件运行时产生一个窗口,当用户双击该窗口的时候,我需要通知调用者: 我的 COM 组件 ...
- Windows和Linux下通用的线程接口
对于多线程开发,Linux下有pthread线程库,使用起来比较方便,而Windows没有,对于涉及到多线程的跨平台代码开发,会带来不便.这里参考网络上的一些文章,整理了在Windows和Linux下 ...
- Kubernetes学习之路(六)之创建K8S应用
一.Deployment的概念 K8S本身并不提供网络的功能,所以需要借助第三方网络插件进行部署K8S中的网络,以打通各个节点中容器的互通. POD,是K8S中的一个逻辑概念,K8S管理的是POD,一 ...
- #2009. 「SCOI2015」小凸玩密室
神仙题啊.完全想不出 首先看方案.可以从任意一个点开始,在这个点要先走完子树,然后走到父亲,再走兄弟,再走父亲的父亲,父亲的兄弟..一直走到1,1的另外一个子树,结束. 完全不会鸭.jpg 设f[i] ...