最近公共祖先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全栈工程师(包、模块 的导入)
ParisGabriel 每天坚持手写 一天一篇 决定坚持几年 为了梦想 为了信仰 Python人工智能从入门到精通 $ pip3 install tenso ...
- JavaSE复习(一)继承多态与常用API
继承与多态 在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式: 直接通过子类对象访问成员变量:等号左边是谁,就优先用谁,没有则向上找 间接通过成员方法访问成员变量:该方法属于 ...
- python中的re模块,常用函数介绍
参考: http://www.cnblogs.com/tina-python/p/5508402.htm ======== 1,预定义字符集,可以写在字符集[....]中 \d 数字: \D 非数字 ...
- 那些牛掰的 HTML5的API(二)
1:视频播放器 2:地理定位 我们的支持html5 的浏览器给我们提供一个接口(api),可以用来获取你当前的位置. 主要是通过geolocation(地理位置),对象 ,去访问硬件,来获取到经纬度. ...
- Android 热更新是如何实现的?
Android开发中,我们常常遇到热更新这个概念,而这个热更新具体是怎么实现的呢?今天在网上看到一个大神分享的热更新相关实现原理和实现代码,感觉灰常不错,分享给广大码农盆友look look . Cl ...
- 【BZOJ1123】 [POI2008]BLO (tarjan)
tarjan判断割点...拿掉一个点之后,会被分成若干个联通块,用节点个数和统计一下他们相互不能到达的个数就好. ; maxm=; type edgetype=record toward,next:l ...
- BZOJ 1036 [ZJOI2008]树的统计Count | 树链剖分模板
原题链接 树链剖分的模板题:在点带权树树上维护路径和,最大值和单点修改 这里给出几个定义 以任意点为根,然后记 size (u ) 为以 u 为根的子树的结点个数,令 v 为 u 所有儿子中 size ...
- 树上莫队 SPOJ COT2
题意: 给一棵树,每次查询u到v路径上有多少不同的点权 首先需要证明这类题目符合区间加减性质 摘选一段vfk大牛的证明 用S(v, u)代表 v到u的路径上的结点的集合. 用root来代表根结点,用l ...
- GDB调试——经验总结
GDB调试的一些很有用经验: 1. gdb调试,如果有参数,可以在run命令后加,也可以使用set args :如果是使用gdbserver+gdb的远程调试方式,参数可以在gdbserver后面加. ...
- H5单文件压缩插件
单文件压缩上传 <input type="file" id="file"> 构造函数 function UpFileImg(options){ va ...