何为LCA(最近共同祖先)?

2024-05-14 06:52
文章标签 lca 最近 共同 祖先 何为

本文主要是介绍何为LCA(最近共同祖先)?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原篇:(ACM算法)tarjan算法求LCA - 知乎 (zhihu.com)

顾名思义,就是求两个节点最近的共同祖先,就好比下图,2和3的共同祖先为3,2和4的共同祖先为1。

关于LCA求解有3种算法。

1.标记回溯法(也称暴力枚举,从一个点开始向上标记他的父节点,直接标记到根节点为止,然后另另一个点也开始向上回溯,当这个点被标记过,则找到这两个点的共同祖先),当数据过大时,很明显这个算法会超时,所以本文不过多解释此方法。

2.ST倍增法(本文也不重点介绍次方法,读者可看其他博客阅读此方法)

3.targan算法(本文重点介绍)

tarjan算法就这几个步骤:
1.标记当前节点x已访问,但是还没有回溯

2.枚举所有没有访问的过的子节点y,继续遍历子节点

3.合并y到x上

4.访问所有与当前节点有询问并且回溯过的y x,y的lca就是find(y)

5.标记当前节点回溯

首先targan是基于并查集实现的,没学过的读者可点击此传送门:何为并查集?-CSDN博客

具体过程看以下代码:

#include<bits/stdc++.h>
#define int long long 
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int> 
using namespace std;
const int N=5e5+5;
int fa[N],vis[N];
vector<int> v[N];
vector<PII> query[N];
int ans[N]; 
int find(int x){//并查集模板 if(fa[x]==x)  return x;else return fa[x]=find(fa[x]);
}
void tarjan(int x){vis[x]++;//第一次走过的路径标记为1 for(auto i :v[x]){if(!vis[i]){//若子节点没走过 继续遍历子节点 tarjan(i);fa[i]=x;//合并子节点到当前节点 }		}for(auto t : query[x]){int a=t.fi,b=t.se;if(vis[a]==2&&!ans[b]) ans[b]=find(a);// 若已经回溯并且b下标为空 }vis[x]++;//回溯的路径标记为2 
}
void solve(){	int n,m,q;cin >> n >> m >> q;for(int i=1;i<n;++i){int x,y;cin >> x >> y;v[x].push_back(y);//将x,y存入数组中 v[y].push_back(x);}for(int i=1;i<=n;++i) fa[i]=i;//预处理所有节点都是自己的父节点 for(int i=1;i<=m;++i){int x,y;cin >> x >> y;if(x==y){//特判 ans[i]=x;continue;}query[x].push_back({y,i});//存入查询的数字 query[y].push_back({x,i});}tarjan(q);for(int i=1;i<=m;++i){cout << ans[i] << endl;}return ;
}
signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;//cin >> t;while(t--) solve();return 0;
}

经典例题:P3884 [JLOI2009] 二叉树问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

解题思路:用层序遍历的思想求出树的深度和宽度,同时标记每个节点所在的层数,然后用tarjan算法求出a和b的共同祖先,最后套公式输出距离即可。

实现代码:

#include<bits/stdc++.h>
#define int long long 
#define endl "\n"
#define fi first
#define se second
#define PII pair<int,int> 
using namespace std;
const int N=105;
vector<int> v[N];
vector<int> s[N];
queue<PII> q;
int a,b;
int vis[N],fa[N],c[N];
vector<PII> query[N];
int ans1,ans2;
int k;
PII pa;
void check(int x){q.push({1,1});c[1]=1;int sum=0;int t=1;while(!q.empty()){pa=q.front();q.pop();if(pa.se==t) sum++;else{ans2=max(ans2,sum);t++;sum=1;}c[pa.fi]=pa.se;for(int i=0;i<s[pa.fi].size();++i){q.push({s[pa.fi][i],pa.se+1});}} ans1=t;ans2=max(ans2,sum);
}
int find(int x){if(fa[x]==x)  return x;else return fa[x]=find(fa[x]);
}
void tarjan(int x){vis[x]++; for(auto i :v[x]){if(!vis[i]){tarjan(i);fa[i]=x;}		}for(auto t : query[x]){int a=t.fi;if(vis[a]==2){k=find(a);break;} }vis[x]++;
}
void solve(){int n;cin >> n;for(int i=1;i<n;++i){int x,y;cin >> x >> y;v[x].push_back(y);v[y].push_back(x);s[x].push_back(y);}	for(int i=1;i<=n;++i) fa[i]=i; cin >> a >> b;query[a].push_back({b,1});query[b].push_back({a,1});check(1);cout << ans1 << endl << ans2 << endl;tarjan(1);//for(int i=1;i<=n;++i) cout << c[i] << endl; cout << (c[a]-c[k])*2+(c[b]-c[k]);return ;
}
signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;//cin >> t;while(t--) solve();return 0;
}

这篇关于何为LCA(最近共同祖先)?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/988050

相关文章

从去中心化到智能化:Web3如何与AI共同塑造数字生态

在数字时代的演进中,Web3和人工智能(AI)正成为塑造未来互联网的两大核心力量。Web3的去中心化理念与AI的智能化技术,正相互交织,共同推动数字生态的变革。本文将探讨Web3与AI的融合如何改变数字世界,并展望这一新兴组合如何重塑我们的在线体验。 Web3的去中心化愿景 Web3代表了互联网的第三代发展,它基于去中心化的区块链技术,旨在创建一个开放、透明且用户主导的数字生态。不同于传统

poj1330(LCA最近公共祖先)

题意:求最近公共祖先 思路:之前学习了树链剖分,然后我就用树链剖分的一小部分知识就可以解这个题目了,记录每个结点的fa和depth。然后查找时,每次将depth大的结点往上走直到x = y。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstring>

最近心情有点复杂:论心态

一月一次的彷徨又占据了整个身心;彷徨源至不自信;而不自信则是感觉自己的价值没有很好的实现亦或者说是自己不认可自己的目前的生活和状态吧。 我始终相信一句话:任何人的生活形态完全是由自己决定的;外在的总归不能直达一个人的内心深处。所以少年 为了自己想要的生活 多坚持努力吧、不为别人只为自己心中的那一丝执着。 由此我看到了一个故事: 一个心情烦躁的人去拜访禅师。他问禅师:我这辈子就这么注定了吗?您

在二叉树中找到两个节点的最近公共祖先(基于Java)

如题  题解 public int lowestCommonAncestor(TreeNode root, int o1, int o2) {//记录遍历到的每个节点的父节点。Map<Integer, Integer> parent = new HashMap<>();Queue<TreeNode> queue = new LinkedList<>();parent.put(roo

[情商-13]:语言的艺术:何为真实和真相,所谓真相,就是别人想让你知道的真相!洞察谎言与真相!

目录 前言: 一、说话的真实程度分级 二、说谎动机分级:善意谎言、中性谎言、恶意谎言 三、小心:所谓真相:只说对自己有利的真相 四、小心:所谓真相:就是别人想让你知道的真相 五、小心:所谓善解人意:就是别人只说你想要听到的话 前言: 何为真实和真相,所谓真相,就是别人想让你知道的真相!洞察谎言与真相! 人与人交流话语中,处处充满了不真实,完全真实的只是其中一小部分,这

算法图解(8~10贪心,动态规划,K最近邻算法)

贪心算法 在每一步都选择局部最优解,从而期望最终得到全局最优解。 贪心算法并不总能保证全局最优解,因此需要满足以下两个条件: 贪心选择性质:可以通过局部最优选择构造出全局最优解。最优子结构:问题的最优解包含其子问题的最优解。 实例:给定面额的硬币,用最少硬币凑出指定金额 int minCoins(vector<int>& coins, int amount) {int count = 0

救命!我已经彻底被最近的FLUX模型征服了

这是一期FLUX模型配套的罗拉模型推荐,这个大模型真的很香,尤其是对于人物的手部处理,推荐大家去尝试下,我已经爱上这个大模型了。 ① Flux魅影超模 https://www.liblib.art/modelinfo/15818662ba2e443d9b4f9a87c13fff55 关键词:照片上是一位优雅的年轻女子,一头棕色卷发,身穿米色上衣,戴着金耳环。她背对着相机,背景是浅色的。重点是

redis 实现单位时间内错误记录 时间到key值就被清除------最近脑子不好使觉得还是写个博客试试

直接在客户端操作的, 所以需要redis的简单命令  去对比JAVA客户端jedis的命令就行   添加---set     格式 set  key  value  EX time(秒)   如果这个time不添加的话 ,那默认就是 永久 获取--get    格式 get key  ---查看剩余时间    格式 TTL key ---实现key实现自增: inrc key

最近刚接触用到的一些linux命令(CentOS7的命令)二〇一八年十月三十日

linux  查看本地     ip  ip addr  查看本地系统     #cat /etc/issue 在CentOS下执行显示为: CentOS release 5.7 (Final) Kernel \r on an \m 或在Ubuntu下显示为: Ubuntu 11.04 \n \l 可以用来查看当前正在运行的 Ubuntu 的版本号。  查看系统内核     uname -a

最近做阿里的笔试题,美团的笔试题都出现了栈的顺序的问题。

问题描述:   已知abcdef,依次入栈,在栈中可停留也可出栈,求下面哪个出栈的顺序不正确?或者有多少种出栈的顺序? f(0):1 f(1):1 f(2):2 f(3):5 f(4):14 f(5):42 f(6):132 所以对于abcdef共有132种顺序 一:对于出栈的顺序 A:fedcbaB:dcbaef // abcd入栈,dcba依次出栈,e入栈,e出