何为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;
}

相关推荐

  1. 最近公共祖先LCA

    2024-05-14 02:20:03       16 阅读
  2. 【模板】最近公共祖先LCA

    2024-05-14 02:20:03       16 阅读
  3. 最近公共祖先LCA)主要算法:

    2024-05-14 02:20:03       35 阅读
  4. 最近公共祖先lca)倍增算法【模板】

    2024-05-14 02:20:03       23 阅读

最近更新

  1. pycharm中快捷键汇总

    2024-05-14 02:20:03       0 阅读
  2. Python爬虫原理以及3个小案例(源码)

    2024-05-14 02:20:03       1 阅读
  3. PySpark 中 RDD 与 DataFrame 的不同应用场景

    2024-05-14 02:20:03       1 阅读
  4. 【OCC学习18】三维几何对象工具包:TKG3d

    2024-05-14 02:20:03       1 阅读
  5. Android 12系统源码_设备设置(一)Settings介绍

    2024-05-14 02:20:03       1 阅读

热门阅读

  1. WXML语法

    2024-05-14 02:20:03       16 阅读
  2. python的面向对象

    2024-05-14 02:20:03       13 阅读
  3. 实用的Chrome命令

    2024-05-14 02:20:03       14 阅读
  4. 软件测试自动化:加速测试,提升效率

    2024-05-14 02:20:03       11 阅读
  5. C语言从头学02——基本语法概念

    2024-05-14 02:20:03       8 阅读
  6. Centos常用命令

    2024-05-14 02:20:03       15 阅读
  7. Oracle数字格式化,有小数就显示,没有就不显示

    2024-05-14 02:20:03       12 阅读
  8. Leetcode 3149. Find the Minimum Cost Array Permutation

    2024-05-14 02:20:03       12 阅读
  9. 代码随想录训练营32day-动态规划5

    2024-05-14 02:20:03       13 阅读
  10. QT--4

    QT--4

    2024-05-14 02:20:03      11 阅读