最近公共祖先(LCA)问题
最近公共祖先
定义:给定一颗有根树,若结点 z 既是 x 的祖先,也是 y 的祖先,则称 z 是 x,y 的公共祖先。在 x,y 所有的公共祖先中,深度最大的一个称为 x,y 的最近公共祖先,简称\(LCA(x,y)\)。
求解最近公共祖先一般有三种解法:向上标记法,树上倍增法和 Tarjan 算法。
1.向上标记法
即对于任何两个结点 x , y ,分别从x y 向上走并标记它们所有经过的节点,第一次相遇的节点即为最近公共祖先。其时间复杂度最坏为\(O(n^2)\)。
2.树上倍增法
树上倍增法在很多问题都有很广泛的应用,当然最近公共祖先也可以用树上倍增算法来求,其基本思想是:
设d[x]>=d[y],其中d[x]表示x的深度,然后利用二进制思想,将x不断调整直至和y在同一深度,检查此时x和y是否相等,若相等即为最近公共祖先,否则将x,y一起向上调整直至相等,此时则为最近公共祖先。
该算法时间复杂度为:\(O((n+m)logn)\)具体代码(裸题,求权值)为:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int head[maxn],dis[maxn],d[maxn],f[maxn][20];
struct Edge
{
int nex,to,val;
}edge[maxn<<1];
int T,t,n,m,tot;
queue<int> q;
void init()
{
tot=0;
memset(head,-1,sizeof(head));
memset(d,0,sizeof(d));
}
void add(int from,int to,int val)
{
edge[++tot].to=to;
edge[tot].val=val;
edge[tot].nex=head[from];
head[from]=tot;
}
void bfs()
{
q.push(1);
d[1]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i!=-1;i=edge[i].nex)
{
int y=edge[i].to;
if(d[y]) continue;
d[y]=d[x]+1;
dis[y]=dis[x]+edge[i].val;
f[y][0]=x;
for(int j=1;j<=t;++j)
f[y][j]=f[f[y][j-1]][j-1];
q.push(y);
}
}
}
int lca(int x,int y)
{
if(d[x]<d[y]) swap(x,y);
for(int i=t;i>=0;--i)
if(d[f[x][i]]>=d[y]) x=f[x][i];
if(x==y) return x;
for(int i=t;i>=0;--i){
if(f[x][i]!=f[y][i]){
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
t=(int)(log(n)/log(2))+1;
init();
for(int i=1;i<n;++i){
int a,b,val;
scanf("%d %d %d",&a,&b,&val);
add(a,b,val);
add(b,a,val);
}
bfs();
for(int i=1;i<=m;++i){
int x,y;
scanf("%d %d",&x,&y);
printf("%d\n",dis[x]+dis[y]-2*dis[lca(x,y)]);
}
}
}
3.Tarjan算法
Tarjan算法本质上是用并查集对“向上标记法”的优化。它是一个离线算法(即将所有输入都输入完成后一起输出);其时间复杂度为:\(O(n+m)\)。
该算法将树中所有结点分成了三类:访问并回溯过,访问但为回溯过,未访问三类。该三类点分别标记为2,1和0。该算法的思想是当一个结点被标记为2时,则将它所在集合合并到它的父节点所在的集合中,这就相当于每个完成回溯的结点都有一个指针指向其父节点,所以只需查询y所在集合的代表元素,就等价与从y一直向上走到一个开始递归但尚未回溯的结点,即\(LCA(x,y)\)。
还是上面的题面,看代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+10;
const int maxe=210;
const int inf=0x3f3f3f3f;
struct Edge
{
int nex,to,val;
}edge[maxn<<1];
int T,n,m,t,tot;
int head[maxn],fa[maxn],v[maxn],dis[maxn],ans[maxe];
vector<int> query[maxn],query_id[maxn];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
memset(dis,0,sizeof(dis));
memset(v,0,sizeof(v));
for(int i=1;i<=n;++i){
fa[i]=i;
query[i].clear();
query_id[i].clear();
}
}
void add(int from,int to,int val)
{
edge[++tot].to=to;
edge[tot].val=val;
edge[tot].nex=head[from];
head[from]=tot;
}
void add_query(int x,int y,int id)
{
query[x].push_back(y);
query_id[x].push_back(id);
query[y].push_back(x);
query_id[y].push_back(id);
}
int ffind(int x)
{
return x==fa[x]?x:fa[x]=ffind(fa[x]);
}
void tarjan(int x)
{
v[x]=1;
for(int i=head[x];i!=-1;i=edge[i].nex)
{
int y=edge[i].to;
if(v[y]) continue;
dis[y]=dis[x]+edge[i].val;
tarjan(y);
fa[y]=x;
}
for(int i=0;i<query[x].size();++i)
{
int y=query[x][i],id=query_id[x][i];
if(v[y]==2){
int lca=ffind(y);
ans[id]=min(ans[id],dis[x]+dis[y]-2*dis[lca]);
}
}
v[x]=2;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
init();
for(int i=1;i<n;++i){
int a,b,val;
scanf("%d %d %d",&a,&b,&val);
add(a,b,val);
add(b,a,val);
}
for(int i=1;i<=m;++i){
int x,y;
scanf("%d %d",&x,&y);
if(x==y) ans[i]=0;
else{
add_query(x,y,i);
ans[i]=inf;
}
}
tarjan(1);
for(int i=1;i<=m;++i)
printf("%d\n",ans[i]);
}
system("pause");
}
最近公共祖先(LCA)问题的更多相关文章
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)
POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- [模板] 最近公共祖先/lca
简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...
- 【lhyaaa】最近公共祖先LCA——倍增!!!
高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...
- POJ 1470 Closest Common Ancestors (最近公共祖先LCA 的离线算法Tarjan)
Tarjan算法的详细介绍,请戳: http://www.cnblogs.com/chenxiwenruo/p/3529533.html #include <iostream> #incl ...
- 【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)
寻找最近公共祖先,示例如下: 1 / \ 2 3 / \ / \ 4 5 6 7 / \ ...
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...
- 查找最近公共祖先(LCA)
一.问题 求有根树的任意两个节点的最近公共祖先(一般来说都是指二叉树).最近公共祖先简称LCA(Lowest Common Ancestor).例如,如下图一棵普通的二叉树. 结点3和结点4的最近公共 ...
- 最近公共祖先(LCA)的三种求解方法
转载来自:https://blog.andrewei.info/2015/10/08/e6-9c-80-e8-bf-91-e5-85-ac-e5-85-b1-e7-a5-96-e5-85-88lca- ...
随机推荐
- python爬虫中图形验证码的处理
使用python爬虫自动登录时,遇到需要输入图形验证码的情况,一个比较简单的处理方法是使用打码平台识别验证码. 使用过两个打码平台,打码兔和若快,若快的价格更便宜,识别率相当.若快需要注册两个帐号:开 ...
- P&R 4
Floorplan 要做好fp需要掌握哪些知识和技能? 通常遇到fp问题大致的debug步骤和方法有哪些? 如何衡量fp的QA? 通常FP是做PR 最关键也最具技术含量的一个环节.相对于后续的PR步骤 ...
- bootstrap fileinput上传文件
参考博客:https://blog.csdn.net/linhaiyun_ytdx/article/details/76215974 https://www.cnblogs.com/parker-y ...
- Error: EACCES: permission denied, open '/Users/qinmengjiao/WebstormProjects/m-kbs-app/.babelrc
表示没有访问这个文件的权限 执行命令 sudo chown -R $(whoami) ~/WebstormProjects/m-kbs-app/.babelrc 就可以解决上面的问题 以下是chown ...
- 一周搞定模拟电路P3_电容_记录
1 电容的介绍 什么是电容 它有两个电极板,和中间板所夹的介质封装而成,具有特定功能的电子器件. 电容的作用 旁路.去耦.滤波和储能的作用 2 旁路电容的作用 1)使输入电压均匀化,减少噪声对后级的影 ...
- opencv:图像的算术操作
前提:输入图像的大小和类型必须一致 越界处理: 大于255,则会减去255 小于0,则等于0 基本计算,加减乘除 #include <opencv2/opencv.hpp> #includ ...
- sqlserver查询使用with(nolock)详解
所有Select加 With (NoLock)解决阻塞死锁 在查询语句中使用 NOLOCK 和 READPAST 处理一个数据库死锁的异常时候,其中一个建议就是使用 NOLOCK 或者 READPAS ...
- 吴裕雄 python 神经网络TensorFlow实现LeNet模型处理手写数字识别MNIST数据集
import tensorflow as tf tf.reset_default_graph() # 配置神经网络的参数 INPUT_NODE = 784 OUTPUT_NODE = 10 IMAGE ...
- Qt QML Component 学习笔记
简介 Component是Qt封装好的.只暴露必要接口的QML类型,可以重复利用.一个QML组件就像一个黑盒子,它通过属性.信号.函数和外部世界交互. 一个Component既可以定义在独立的QML文 ...
- cnpm - 解决 " cnpm : 无法加载文件 C:\Users\93457\AppData\Roaming\npm\cnpm.ps1,因为在此系统上禁止运行脚本。有关详细信息 。。。 "
1.在win10 系统中搜索框 输入 Windos PowerShell选择 管理员身份运行 2,打开了powershell命令行之后,输入 set-ExecutionPolicy RemoteSig ...