LCA-最近公共祖先总结
简介
作用
求树上两点最短路径。
朴素算法
不停找爸爸祖先,共同访问的第一个即最近公共祖先。
倍增
why?
具有单调性,最近公共祖先的祖先同样是公共祖先。
思路:
-
将
变成同一深度的。(同步调整深度) -
由大到小倍增同步跳转,找到公共祖先的下一个点(再上一步就是答案,防止跳过头)。
实现思路:
通过预处理
求法
使用动态规划思想,状态转移方程为:
(第
代码~~
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+10;
int n,m,root,x,y,nm;
int head[N],
f[N][20],//第 i 个点的第 2^j 个祖先
dep[N];//第 i 个点 的深度,定义 根节点 深度为 1
struct sb{
int to,next;
}e[N*2];
void ae(int from,int to) {
e[++nm].to=to;
e[nm].next=head[from];
head[from]=nm;
}
void dfs(int from,int fa) {
dep[from]=dep[fa]+1;
for(int i=head[from];i;i=e[i].next) {
int to=e[i].to;
if(to==fa) continue;
f[to][0]=from;
for(int k=1;1<<k<=dep[from];k++) {
f[to][k]=f[f[to][k-1]][k-1];//预处理 fa
}
dfs(to,from);
}
}
int lca(int x,int y) {
if(dep[x]<dep[y]) {
swap(x,y);// 默认为将 x 调整至 y
}
for(int i=19;i>=0;i--) {
if(dep[f[x][i]]>=dep[y])//跳至同一高度
x=f[x][i];
}
if(x==y) return y;//在同一个高度,是一个节点 -> y为 LCA
for(int i=19;i>=0;i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];//倍增同步跳转 跳到的是 LCA 的儿子
return f[x][0];//父节点就是 LCA
}
int main() {
cin>>n>>m>>root;
for(int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
ae(x,y),ae(y,x);
}
dfs(root,0);//从根开始
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0;
}
tarjan
代码~~
以下为 tarjan 带权求离线最短路代码
#include<bits/stdc++.h>
using namespace std;
#define pll pair<int,int>
const int N = 5e5+10;
struct sb{
int dis,next,to;
}edge[N*2];
int fa[N],dis[N],res[N],head[N],n,m,nm;
bool vis[N];
vector<pll >vec[N];
void ae(int from,int to,int dis) {
edge[++nm].dis=dis;
edge[nm].next=head[from];
edge[nm].to=to;
head[from]=nm;
}
int find(int x) {if(x!=fa[x]) return fa[x]=find(fa[x]);return fa[x];}
void dfs(int from) {
vis[from]=1;
for(int i=head[from];i;i=edge[i].next) {
int to=edge[i].to;
if(!vis[to]) {
dis[to]=dis[from]+edge[i].dis;
dfs(to);
fa[to]=from;
}
}
for(int i=0;i<vec[from].size();i++) {
int to=vec[from][i].first,id=vec[from][i].second;
if(vis[to]) res[id]=dis[to]+dis[from]-2*dis[find(to)];
}
}
int main() {
cin>>n>>m;
for(int i=1;i<n;i++) {
int x,y,z;
cin>>x>>y>>z;
ae(x,y,z),ae(y,x,z);
}
for(int i=1;i<=n;i++) {
fa[i]=i;
}
for(int i=1;i<=m;i++) {
int x,y;
cin>>x>>y;
vec[x].push_back({y,i});
vec[y].push_back({x,i});
}
dfs(1);
for(int i=1;i<=m;i++) {
cout<<res[i]<<"\n";
}
}
本文作者:cjrqwq
本文链接:https://www.cnblogs.com/yfzqwq/p/18492826
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步