当前位置: 首页 > news >正文

【笔记】最近公共祖先 Tarjan 算法

该算法可以离线求最近公共祖先,大幅节省时间复杂度(\(O(n \log n)\)->\(O(n+m)\))。

缺点是如果题目要求强制在线那么就用不了了。

具体实现是这样的:把原树用双向边存起来,然后把每一对要求 LCA 的两个点在一个新图上存一个双向边(称为查询边)。

对原图进行一次 DFS 遍历,遍历过程中使用并查集存储每个节点的祖先。我们在遍历过程中往下遍历时节点的祖先是它本身,遍历完这个节点的子树后回溯时是它的父亲。回溯过程中遍历到以 \(v\) 为根的子树时,如果 \(i\) 节点恰好访问过,而并查集中存储的又正是 \(v\) 的最近祖先,那么 \(v\) 的最近祖先就恰好是两个点的最近公共祖先。将查询边中 \(v\)\(i\) 节点的 LCA 设为并查集中存储 \(v\) 的祖先(即 \(v\) 的父亲)即可。

时间复杂度涉及 \(3\) 个要素,一个是 DFS 的时间复杂度 \(O(n)\),一个是并查集的初始化 \(O(n)\),一个是路径压缩优化过后的并查集时间复杂度 \(O(a(n))\),其中 \(a\) 表示的是阿克曼函数的反函数,增长极其缓慢,常数最大到 \(4\) 左右。总时间复杂度 \(O(n+m)\) 左右。去掉了倍增法的 \(\log\),但是常数会比倍增法大。

在 LCA 模板题中,可以看到两次提交差别非常大:

在线算法倍增:

离线算法 Tarjan:

可以注意到因为常数较大导致前面的小点跑得反而慢,但是后面的大点快了将近 2 倍。

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=5e5+10;
struct Node{int to,nxt,LCA;
}e[2*maxn],q[2*maxn];
int n,m,s,D;
int tot,h[maxn],hq[maxn];
int fa[maxn];
bool vis[maxn];
void Add(int u,int v){tot++;e[tot].to=v;e[tot].nxt=h[u];h[u]=tot;
}
void Addq(int u,int v){tot++;q[tot].to=v;q[tot].nxt=hq[u];hq[u]=tot;
}
int Find(int x){if(fa[x]==x) return x;else return fa[x]=Find(fa[x]);
}
void tarjan(int u){fa[u]=u;vis[u]=1;for(int i=h[u];i!=-1;i=e[i].nxt){int v=e[i].to;if(!vis[v]){tarjan(v);fa[v]=u;}}for(int i=hq[u];i!=-1;i=q[i].nxt){int v=q[i].to;if(vis[v]){if(i%2==0) q[i-1].LCA=q[i].LCA=Find(v);else q[i+1].LCA=q[i].LCA=Find(v);}}
}
int main(){memset(h,-1,sizeof(h));memset(hq,-1,sizeof(hq));scanf("%d%d%d",&n,&m,&s);for(int i=1;i<=n-1;i++){int x,y;scanf("%d%d",&x,&y);Add(x,y);Add(y,x);}	tot=0;for(int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);Addq(a,b);Addq(b,a);}tarjan(s);for(int i=1;i<=2*m;i+=2){printf("%d\n",q[i].LCA);}return 0;
}
http://www.jsqmd.com/news/79281/

相关文章:

  • 2025 最新家政保洁平台服务商 TOP5 评测!优质家政保洁服务公司深度解析,重构家居生活服务新生态 - 全局中转站
  • Notepad(文本编辑器)v3.6.30绿色官方版
  • Spring的DI依赖注入(配置文件方式)
  • Office Tool Plus v10.29.50 office安装激活一条龙
  • 在写小故事(实则是高中回忆录)
  • 【题解】Luogu P1081 [NOIP2012 提高组] 开车旅行
  • 2025年AI图文创作神器01Agent:3步解决‘死图‘痛点,效率提升300%
  • 2025年AI图文创作神器01Agent:3步解决‘死图‘痛点,效率提升300%
  • 如何编写优美的代码:从工匠到艺术家的修炼之路
  • 做字幕不再靠 Pr?一次带你体验真正的省时做法
  • AI搜索焦虑自救指南:一份面向2026年的系统化追赶方案
  • 常见报错org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): org.example.dem
  • 【题解】Codeforces 1986B Matrix Stabilization
  • 【题解】Luogu P6092 [CEOI2012] 工作规划
  • 告别文件整理拖延症!快速找关键字 TXT + 批量复制到目标文件夹,躺平搞定
  • [Non]树上乘法
  • 【笔记】强连通分量
  • 告别信息传递繁琐步骤!批量查询+手机条形码一键发,1次搞定全传递
  • 视频剪辑软件电脑版排行榜,2025年度前十名软件推荐
  • 《追问者宪章》完整版
  • 重练算法(代码随想录版) day38 - 动态规划part6
  • 笑不活!男人假装爱你,7 个 “演技信号” 速查!
  • 1-Year XTOOL D9 Update Service: Latest Diagnostics for European/American Vehicles
  • 【笔记】最近公共祖先 Tarjan
  • Error occurred during initialization of VMCould not reserve enough space for object heap
  • 【算法题】滑动窗口(一)
  • 东芝与Quantum Corridor实现量子安全网络通信重大突破
  • 基于java的SpringBoot/SSM+Vue+uniapp的零工市场服务系统的详细设计和实现(源码+lw+部署文档+讲解等)
  • 为什么越来越多的IT技术人员转行网络安全?零基础入门到精通,收藏这一篇就够了
  • 甲骨文AI投资支出激增致股价创24年最大跌幅