最近公共祖先LCA Tarjan 离线算法
【简介】
解决LCA问题的Tarjan算法利用并查集在一次DFS(深度优先遍历)中完成所有询问。换句话说,要所有询问都读入后才开始计算,所以是一种离线的算法。
【原理】
先来看这样一个性质:当两个节点(u,v)的最近公共祖先是x时,那么我们可以确定的说,当进行后序遍历的时候,必然先访问完x的所有子树,其中包含u、v,然后才会返回到x所在的节点。这个性质就是我们使用Tarjan算法解决最近公共祖先问题的核心思想。

如上图所示,找出根节点到u得关键路径P ,已遍历的点位于路径P中某个点的子树中,当遍历到u时v已遍历过(u的子树已遍历完),那么v必然存在于子树pk中,此时LCA(u,v)就等于现在v所在集合的祖先pk。如果还没有遍历到,则继续遍历,只不过LCA(u,v)要等到遍历到v时才能知道了,原理如上。需要注意的一点是,为了保持上图的性质,如果一个节点的一个子树遍历完了,需要合并该节点的子树集合。
tarjan算法的步骤是(当dfs到节点u时):
(一) 在并查集中建立仅有u的集合,设置该集合的祖先为u
(二) 对u的每个孩子v:
1. tarjan之
2. 合并v到父节点u的集合,确保集合的祖先是u
(三)设置u为已遍历
(四)处理关于u的查询,若查询(u,v)中的v已遍历过,则LCA(u,v)= v所在的集合的祖先
【举例】
![]() |
假设遍历完10的孩子,要处理关于10的请求了 可以发现集合的祖先便是LCA ! |
【HDU 2586】
换成Tarjan 离线算法来做。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <string.h>
#include <vector>
#include <cmath>
using namespace std;
int n,m;
struct edge
{
int d,v,next;
edge(){}
edge(int _d,int _v,int _next)
{
d=_d;v=_v;next=_next;
}
}data[];
int map[];
int pool;
void addedge(int s,int e,int v)
{
int t=map[s];
data[pool++]=edge(e,v,t);
map[s]=pool-;
}
int mset[];
int find(int k)
{
if (mset[k]==-) return k;
return mset[k]=find(mset[k]);
}
void uion(int a,int b)
{
int aa=find(a);
int bb=find(b);
mset[aa]=bb;
}
struct _que
{
int a,b;
_que(int q=,int w=){a=q;b=w;}
};
vector<vector<_que> > ques;
vector<int > ans;
int ifv[];
int dis[];
int anc[];
void tar(int cur)
{
ifv[cur]=;
anc[cur]=cur;
int p=map[cur];
while (p!=-)
{
if (!ifv[data[p].d])
{
dis[data[p].d]=dis[cur]+data[p].v;
tar(data[p].d);
uion(cur,data[p].d);
anc[find(cur)]=cur;
}
p=data[p].next;
}
ifv[cur]=;
for (int i=;i<(int)ques[cur].size();++i)
{
if (ifv[ques[cur][i].a]==)
ans[ques[cur][i].b]=dis[cur]+dis[ques[cur][i].a]-*dis[anc[find(ques[cur][i].a)]];
}
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
ques.clear();
pool=;
memset(map,-,sizeof map);
memset(ifv,,sizeof ifv);
memset(mset,-,sizeof mset);
scanf("%d%d",&n,&m);
ques.resize(n);
int s,e,v;
for (int i=;i<n-;++i)
{
scanf("%d%d%d",&s,&e,&v);
addedge(s-,e-,v);
addedge(e-,s-,v);
}
dis[]=;
ans.resize(m);
for (int i=;i<m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
--u;--v;
ques[u].push_back(_que(v,i));
ques[v].push_back(_que(u,i));
}
tar();
for (int i=;i<(int)ans.size();++i)
{
printf("%d\n",ans[i]);
}
}
}
最近公共祖先LCA Tarjan 离线算法的更多相关文章
- LCA最近公共祖先(Tarjan离线算法)
这篇博客对Tarjan算法的原理和过程模拟的很详细. 转载大佬的博客https://www.cnblogs.com/JVxie/p/4854719.html 第二次更新,之前转载的博客虽然胜在详细,但 ...
- LCA(最近公共祖先)--tarjan离线算法 hdu 2586
HDU 2586 How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/ ...
- POJ 1470 Closest Common Ancestors (最近公共祖先LCA 的离线算法Tarjan)
Tarjan算法的详细介绍,请戳: http://www.cnblogs.com/chenxiwenruo/p/3529533.html #include <iostream> #incl ...
- POJ1470Closest Common Ancestors 最近公共祖先LCA 的 离线算法 Tarjan
该算法的详细解释请戳: http://www.cnblogs.com/Findxiaoxun/p/3428516.html #include<cstdio> #include<alg ...
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现——转载自Vendetta Blogs
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...
- HDU-2586-How far away(LCA Tarjan离线算法)
链接:https://vjudge.net/problem/HDU-2586 题意: 勇气小镇是一个有着n个房屋的小镇,为什么把它叫做勇气小镇呢,这个故事就要从勇气小镇成立的那天说起了,修建小镇的时候 ...
- 最近公共祖先 LCA Tarjan算法
来自:http://www.cnblogs.com/ylfdrib/archive/2010/11/03/1867901.html 对于一棵有根树,就会有父亲结点,祖先结点,当然最近公共祖先就是这两个 ...
- HihoCoder 1067 最近公共祖先(ST离线算法)
最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个 ...
随机推荐
- 孤荷凌寒自学python第五天初识python的列表
孤荷凌寒自学python第五天 列表 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 粗俗地区分列表,可以这样理解,定义或print列表后显示时,列表中的各元素都是用一个方括号[]括起来的. ...
- 201621123033 《Java程序设计》第7周学习总结
1. 本周学习总结 1.1 思维导图:Java图形界面总结 2.书面作业 1. GUI中的事件处理 1.1 写出事件处理模型中最重要的几个关键词. 事件源:事件发生的场所,具体指各个组件. 事件:组件 ...
- tomcat调优(Mark)
http://blog.csdn.net/jinwanmeng/article/details/7756591
- TypeScript & Angular
TypeScript https://github.com/Microsoft/TypeScript https://www.typescriptlang.org/ https://www.type ...
- 类复制 MemberwiseClone与Clone(深 浅 Clone)
MemberwiseClone 方法创建一个浅表副本,具体来说就是创建一个新对象,然后将当前对象的非静态字段复制到该新对象.如果字段是值类型的,则对该字段执行逐位复制.如果字段是引用类型,则复制引用但 ...
- android Toolbox和BusyBox
在安卓系统中,Toolbox是能够实现内存的管理,备份管理和清除数据等功能的系统文件.用来对手机性能进行设置,需要root权限.能够被软件调用. 我们在updater-script文件中,知道有类似s ...
- 如何用cookie保存用户的登录的密码和用户名
思路:绘制一个简单的登录界面的Servlet并要在此页面中读取保存密码和用户名的cookie--->在登录处理界面的servlet中把用户名和密码保存到cookie中 //登录界面的Servle ...
- Waifu2x测试
真的是好玩..给大家(?)提供一个能用Waifu2x upscale的图片类型集合.. 上面是原图下面是Upscaled..因为是png大家自行下载对比..
- DatacontractAttribute的使用规则
关于DatacontractAttribute的使用规则和说明, DatacontractAttribute是序列化类的另一种方法,和XmlMemberAttribute(也就是XmlElementA ...
- laravel 学习笔记 —— 神奇的服务容器
转载自:https://www.insp.top/learn-laravel-container 容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器.一个容器能够装什么,全部取决于 ...
