当前位置: 首页 > 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/79257/

相关文章:

  • Error occurred during initialization of VMCould not reserve enough space for object heap
  • 【算法题】滑动窗口(一)
  • 东芝与Quantum Corridor实现量子安全网络通信重大突破
  • 基于java的SpringBoot/SSM+Vue+uniapp的零工市场服务系统的详细设计和实现(源码+lw+部署文档+讲解等)
  • 为什么越来越多的IT技术人员转行网络安全?零基础入门到精通,收藏这一篇就够了
  • 甲骨文AI投资支出激增致股价创24年最大跌幅
  • 基于java的SpringBoot/SSM+Vue+uniapp的旅游出行指南系统的详细设计和实现(源码+lw+部署文档+讲解等)
  • HTTP协议在C#大文件上传中如何处理重试逻辑?
  • 转行IT最吃香的六大岗位:从零到精通,就业无忧!
  • 【笔记】基本数论
  • 19、将 Snort 规则转换为 iptables 规则
  • 计算计算机专业内卷严重,普通毕业生何去何从?​这个风口行业缺口炸了,现在入行正当时!
  • 【Java毕设全套源码+文档】于 SpringBoot的干洗店预约洗衣系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • 23、深入解析 fwsnort 与 psad 的协同防御机制
  • 24、结合 psad 和 fwsnort 增强网络安全防护
  • 22、深入解析fwsnort:网络攻击检测与响应的利器
  • 【Java毕设全套源码+文档】基于 Web 的高校教师工作量管理系统设计与实现(丰富项目+远程调试+讲解+定制)
  • Qt Creator中pro文件添加外部动态库的方法
  • 芯祥联科技SNMP协议栈产品形态
  • 【笔记】状压 DP
  • 基于java的SpringBoot/SSM+Vue+uniapp的篮球管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
  • 【题解】Luogu P5905【模板】全源最短路(Johnson)
  • 基于SpringBoot的宠物识别小程序的设计与实现毕业设计项目源码
  • 基于SpringBoot的传统服饰订制系统毕业设计项目源码
  • 美团原生AI编辑器
  • 基于SpringBoot的大学生体测数据管理系统毕业设计项目源码
  • P3258 [JLOI2014] 松鼠的新家
  • K8S 中使用 YAML 安装 ECK
  • 如何更详细地应用AI提升学习效率?——大学生实战指南
  • 2025 最新租房/找房平台 TOP4 评测!数智化赋能 + 全维服务权威榜单发布,重构居家生活服务新生态 - 全局中转站