参考博客: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算法大致实现过程

  1. 先选择一个节点u为根节点,从根节点开始搜索。(标记u已访问过)
  2. 遍历该点u的所有儿子节点v,并标记v已访问过。
  3. 若v还有儿子节点,对v重复ii操作,否则进入下一操作。
  4. 把v合并到u上(并查集)。
  5. 把当前的点设为u,遍历与u有询问关系的节点v。
  6. 如果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(最近公共祖先)算法的更多相关文章

  1. Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)

    Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...

  2. LCA近期公共祖先

    LCA近期公共祖先 该分析转之:http://kmplayer.iteye.com/blog/604518 1,并查集+dfs 对整个树进行深度优先遍历.并在遍历的过程中不断地把一些眼下可能查询到的而 ...

  3. LCA 近期公共祖先 小结

    LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...

  4. lca 最近公共祖先

    http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...

  5. LCA(最近公共祖先)模板

    Tarjan版本 /* gyt Live up to every day */ #pragma comment(linker,"/STACK:1024000000,1024000000&qu ...

  6. CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )

    CodeVs.1036 商务旅行 ( LCA 最近公共祖先 ) 题意分析 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从 ...

  7. LCA最近公共祖先 ST+RMQ在线算法

    对于一类题目,是一棵树或者森林,有多次查询,求2点间的距离,可以用LCA来解决.     这一类的问题有2中解决方法.第一种就是tarjan的离线算法,还有一中是基于ST算法的在线算法.复杂度都是O( ...

  8. LCA(最近公共祖先)之倍增算法

    概述 对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. 如图,3和5的最近公共祖先是1,5和2的最近公共祖先是4 在本篇中我们先介 ...

  9. LCA最近公共祖先(Tarjan离线算法)

    这篇博客对Tarjan算法的原理和过程模拟的很详细. 转载大佬的博客https://www.cnblogs.com/JVxie/p/4854719.html 第二次更新,之前转载的博客虽然胜在详细,但 ...

  10. 最近公共祖先算法LCA笔记(树上倍增法)

    Update: 2019.7.15更新 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了. 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了 ...

随机推荐

  1. 性能测试loadrunner安装

    把杀毒软件关闭 1. 点击 HP_LoadRunner_12.02_Community_Edition_T7177-15059.exe 完成后,点击下一步 接受协议 点击安装 点击完成 TOOLS - ...

  2. 20145209刘一阳《JAVA程序设计》第三周课堂测试

    第三周课堂测试 1.使用汇编语言编写指令时,用一些简单的容易记忆的符号来代替二进制指令,比机器语言更为方便,属于高级语言.(B) A .true B .false 2.下列说法正确的是(ABCD) A ...

  3. JavaEE笔记(六)

    实现Action的几种方法1. implements Action2. extends ActionSupport3. 也可以不继承任何父类不实现任何借口 #当一个类有多个方法 package com ...

  4. PPAS的MTK tool 工具使用说明

    磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面: PostgreSQL基础知识与基本操作索引页     回到顶级页面:PostgreSQL索引页 [作者 高健@博客园  luckyjackg ...

  5. PyQt5 简易计算器

    剩下计算函数(self.calculator)未实现,有兴趣的朋友可以实现它 [知识点] 1.利用循环添加按钮部件,及给每个按钮设置信号/槽 2.给按钮设置固定大小:button.setFixedSi ...

  6. 一维码ITF 25简介及其解码实现(zxing-cpp)

    一维码ITF 25又称交插25条码,常用在序号,外箱编号等应用.交插25码是一种条和空都表示信息的条码,交插25码有两种单元宽度,每一个条码字符由五个单元组成,其中二个宽单元,三个窄单元.在一个交插2 ...

  7. Kubernetes学习之路(十)之资源清单定义

    一.Kubernetes常用资源 以下列举的内容都是 kubernetes 中的 Object,这些对象都可以在 yaml 文件中作为一种 API 类型来配置. 类别 名称 工作负载型资源对象 Pod ...

  8. cjoj P1435 - 【模板题 USACO】AC自动机 && 洛谷 P3796 【模板】AC自动机(加强版)

    又打了一遍AC自动稽. 海星. 好像是第一次打trie图,很久以前就听闻这个思想了.OrzYYB~ // It is made by XZZ #include<cstdio> #inclu ...

  9. Linux下通过进程名查询占用的端口

    1.首先根据名称用ps命令查看进程ID: ps -ef | grep zookeeper jim 10997 1959 0 12月14 pts/2 00:00:01 /usr/lib/jvm/java ...

  10. vue复习(二)

    一.组件介绍 每一个组件都是一个vue实例 每个组件均具有自身的模板template,根组件的模板就是挂载点 每个组件模板只能拥有一个根标签 子组件的数据具有作用域,以达到组件的复用 二.局部组件 & ...