tarjan算法的步骤是(当dfs到节点u时):
1 在并查集中建立仅有u的集合,设置该集合的祖先为u
1 对u的每个孩子v:
   1.1 tarjan之
   1.2 合并v到父节点u的集合,确保集合的祖先是u
2 设置u为已遍历
3 处理关于u的查询,若查询(u,v)中的v已遍历过,则LCA(u,v)=v所在的集合的祖先

不懂请点击

伪代码:

Tarjan(u)//marge和find为并查集合并函数和查找函数
{
for each(u,v) //访问所有u子节点v
{
Tarjan(v); //继续往下遍历
marge(u,v); //合并v到u上
标记v被访问过;
}
for each(u,e) //访问所有和u有询问关系的e
{
如果e被访问过;
u,e的最近公共祖先为find(e);
}
}

模板:

 #include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = ; int rank[maxn]; //并查集结点高度
int pre[maxn]; //并查集父节点
int anc[maxn]; //祖先
int indgree[maxn]; //保存每个节点的入度
bool vis[maxn];
vector<int> tree[maxn]; //保存树
vector<int> qes[maxn]; //保存查询
int vertex_num; //顶点数 void init()
{
memset(rank,,sizeof(rank));
memset(vis,,sizeof(vis));
memset(indgree,,sizeof(indgree));
memset(anc,,sizeof(anc));
for(int i=;i<=vertex_num;i++){
pre[i] = i;
tree[i].clear();
qes[i].clear();
}
} int find_pre(int x) //查找函数
{
if(pre[x] == x){
return x;
}
else{
pre[x] = find_pre(pre[x]); //压缩路径
}
return pre[x];
} void Union(int x,int y)
{
x = find_pre(x);
y = find_pre(y);
if(x == y){
return ;
}
else{
if(rank[x] > rank[y]){
pre[y] = x;
}
else if(rank[x] == rank[y]){ //x和y深度相同时, y向x合并
rank[x]++;
pre[y] = x;
}
else{
pre[x] = y;
}
}
} int lca(int u)
{
anc[u] = u;
for(int i=;i<tree[u].size();i++){
lca(tree[u][i]);
Union(u,tree[u][i]);
anc[find_pre(u)]=u;
}
vis[u] = ;
for(int i=;i<qes[u].size();i++){
if(vis[qes[u][i]] == ){
return anc[find_pre(qes[u][i])];
}
}
} int main()
{
cout<<"请输入顶点数:";
cin>>vertex_num;
init();
int u,v,ans;
cout<<"请依次输入各边:\n";
for(int i=;i<vertex_num;i++){
cin>>u>>v;
tree[u].push_back(v);
indgree[v]++;
}
cout<<"请输入要查询的两个数:";
cin>>u>>v;
qes[u].push_back(v);
qes[v].push_back(u);
for(int i=;i<=vertex_num;i++){
if(indgree[i] == ){
ans = lca(i);
printf("(%d,%d)的LCA是:%d\n",u,v,ans);
break;
}
}
return ;
}

上一个图,来测试模板:

题目:POJ 1470

代码:点击

/*
* POJ 1470
* 给出一颗有向树,Q个查询
* 输出查询结果中每个点出现次数
*/
/*
* LCA离线算法,Tarjan
* 复杂度O(n+Q);
*/

LCA(最近公共祖先)——离线 Tarjan 算法的更多相关文章

  1. POJ 1330 LCA最近公共祖先 离线tarjan算法

    题意要求一棵树上,两个点的最近公共祖先 即LCA 现学了一下LCA-Tarjan算法,还挺好理解的,这是个离线的算法,先把询问存贮起来,在一遍dfs过程中,找到了对应的询问点,即可输出 原理用了并查集 ...

  2. 图论-最近公共祖先-离线Tarjan算法

    有关概念: 最近公共祖先(LCA,Lowest Common Ancestors):对于有根树T的两个结点u.v,最近公共祖先表示u和v的深度最大的共同祖先. Tarjan是求LCA的离线算法(先存储 ...

  3. P5836 [USACO19DEC]Milk Visits S 从并查集到LCA(最近公共祖先) Tarjan算法 (初级)

    为什么以它为例,因为这个最水,LCA唯一黄题. 首先做两道并查集的练习(估计已经忘光了).简单来说并查集就是认爸爸找爸爸的算法.先根据线索理认爸爸,然后查询阶段如果发现他们的爸爸相同,那就是联通一家的 ...

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

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

  5. POJ1330Nearest Common Ancestors——近期公共祖先(离线Tarjan)

    http://poj.org/problem? id=1330 给一个有根树,一个查询节点(u,v)的近期公共祖先 836K 16MS #include<iostream> #includ ...

  6. [HDOJ2586]How far away?(最近公共祖先, 离线tarjan, 并查集)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 这题以前做过…现在用tarjan搞一发…竟然比以前暴力过的慢………… 由于是离线算法,需要Que ...

  7. POJ 1986 Distance Queries (最近公共祖先,tarjan)

    本题目输入格式同1984,这里的数据范围坑死我了!!!1984上的题目说边数m的范围40000,因为双向边,我开了80000+的大小,却RE.后来果断尝试下开了400000的大小,AC.题意:给出n个 ...

  8. 近期公共祖先(LCA)——离线Tarjan算法+并查集优化

    一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...

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

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

  10. LCA最近公共祖先——Tarjan模板

    LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. Tarjan是一种离线算法,时间复杂度O(n+Q),Q表示询问次数,其中 ...

随机推荐

  1. Ajax全接触(1)

    Ajax全称:Asynchronous JavaScript and XML(异步的JavaScript和XML) .Ajax不是某种编程语言 是一种在无需重新加载整个网页的情况之下能够更新部分网页的 ...

  2. vue源码解读1

    前言 vue是一个非常典型的MVVM框架,它的核心功能一是双向数据绑定系统,二是组件化开发系统.那么本文是以一种通俗易懂的的角度来实现一个简单 的双向数据绑定系统,如果你用过vue却对vue的实现原理 ...

  3. 菜鸟笔记 -- Chapter 6.3 对象

    6.3 对象 Java是一门面向对象的程序设计语言,对象是由类抽象出来的,所有的问题都是通过对象来处理的,对象可以操作类的属性和方法解决相应的问题,所以了解对象的产生.操作和生存周期对学习Java语言 ...

  4. java之递归学习

    递归思想(2018-10-22): 递归就是方法里调用自身 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口 递归算法代码显得很简洁,但递归算法解题的运行效率较低.所以不提倡用递归设计程序 ...

  5. Python常用模块之re

    1.正则表达式规则 2.Python正则常用模块 2.1.re.match与re.search 函数说明:re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match ...

  6. 快速玩转linux(1)

    快速上手Linux玩转典型应用 mark 大牛都会使用Linux, Linux命令是行业要求. 商业服务器基本都是linux 开源软件都先支持Linux(只支持) 大数据分析.机器学习首选Linux ...

  7. Python基础——字典和有序字典

    字典 说明: 在 Python 中, 字典 是一系列 键 — 值对 .每个键都与一个值相关联,你可以使用键来访问与之相关联的值.与键相关联的值可以是数字.字符串.列表乃至字典.事实上,可将任何 Pyt ...

  8. JDK8 新特性

    JDK8 新特性目录导航: Lambda 表达式 函数式接口 方法引用.构造器引用和数组引用 接口支持默认方法和静态方法 Stream API 增强类型推断 新的日期时间 API Optional 类 ...

  9. Python的virtualenv你用过吗?

    1. 为什么要有virtualenv 在使用 Python 开发的过程中,工程一多,难免会碰到不同的工程依赖不同版本的库的问题: 亦或者是在开发过程中不想让物理环境里充斥各种各样的库,引发未来的依赖灾 ...

  10. Yii 2.0.6 - 从入口到Action执行

    defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); r ...