【板子】LCA Tarjan

发布时间:2026/7/28 10:17:31

【板子】LCA Tarjan
这是一份基于 Tarjan塔扬算法的最近公共祖先LCA模板及详细讲解。该算法利用离线处理和并查集的思想是目前求解 LCA 问题最高效的算法之一时间复杂度 O(NQ)其中 N 为节点数Q 为询问数。1. 算法核心讲解核心思想离线 并查集Tarjan 算法是一种离线算法意味着你需要先读入所有的查询请求然后一次性处理完所有答案而不是像在线算法那样问一个答一个。它的巧妙之处在于利用了深度优先搜索DFS回溯时的信息结合并查集来维护当前的“祖先”关系。算法步骤解析初始化每个节点的父节点指向自己fa[i] i。标记所有节点未访问vis[i] false。深度优先搜索 (DFS)进入节点时标记当前节点u为已访问vis[u] true。递归子节点遍历u的所有子节点v。如果v未被访问则递归处理v并在回溯时将v的父节点指向u合并集合。处理查询关键步骤当从子节点回溯到当前节点u时检查所有以u为端点的查询(u, v)。如果节点v已经被访问过说明v所在的子树已经遍历完毕那么v当前的并查集根节点find(v)就是u和v的最近公共祖先LCA。为什么这样做是对的当 DFS 回溯到节点u时意味着u的子树已经全部遍历完成。此时所有在u子树中的节点它们的并查集都会指向u或者u的某个祖先。如果此时发现查询的另一个节点v已经被访问过说明v不在当前子树中那么它们的公共祖先只能是当前路径上深度较浅的那个节点也就是此时的并查集根节点。2. C 代码模板这是一个通用的 Tarjan LCA 模板支持多组查询。#include iostream #include vector #include cstring using namespace std; const int N 50010; // 节点最大数量 const int M 1000010; // 查询最大数量 // 存图邻接表 vectorint e[N]; // 存查询query[u] 中存储 pair查询的另一个点, 查询的ID vectorpairint, int query[N]; int fa[N]; // 并查集数组 bool vis[N]; // 访问标记数组 int ans[M]; // 存储查询结果ans[id] 表示第 id 个查询的答案 // --- 并查集模板 --- int find(int u) { if (u fa[u]) return u; return fa[u] find(fa[u]); // 路径压缩 } // --- Tarjan 算法核心 --- void tarjan(int u) { vis[u] true; // 1. 进入节点 u标记为已访问 // 2. 遍历所有邻接点子节点 for (auto v : e[u]) { if (!vis[v]) { tarjan(v); // 递归处理子树 fa[v] u; // 回溯时将子节点指向父节点合并集合 } } // 3. 处理所有以 u 为起点的查询 for (auto q : query[u]) { int v q.first; int id q.second; // 如果另一个节点 v 已经被访问过说明找到了 LCA if (vis[v]) { ans[id] find(v); // find(v) 即为 u 和 v 的最近公共祖先 } } } int main() { int n, m; // n 个节点m 个查询 cin n m; // 初始化并查集和访问标记 for (int i 1; i n; i) { fa[i] i; vis[i] false; } // 读入 n-1 条边 for (int i 1; i n; i) { int a, b; cin a b; e[a].push_back(b); e[b].push_back(a); } // 读入 m 个查询 for (int i 1; i m; i) { int a, b; cin a b; // 为了处理双向查询将 (b, i) 存入 a 的列表(a, i) 存入 b 的列表 query[a].push_back({b, i}); query[b].push_back({a, i}); } // 从根节点通常设为1开始跑 Tarjan tarjan(1); // 输出结果 for (int i 1; i m; i) { cout ans[i] endl; } return 0; }3. 复杂度分析时间复杂度DFS 遍历遍历整棵树复杂度为 O(N)。并查集操作每次find操作近似 O(1)路径压缩后。处理查询每个查询被处理两次存正反两个方向总复杂度为 O(Q)。总计O(NQ)。空间复杂度O(NQ)主要用于存储图、查询列表和并查集数组。4. 注意事项离线算法如果你需要实时获取某个查询的答案这个算法不适用应选择倍增法或树链剖分等在线算法。多组数据在竞赛中通常需要处理多组测试数据记得每次循环内重置数组特别是e[],query[],vis[]等。根节点选择代码中默认以节点1作为树的根节点开始 DFS这通常符合题目要求。

相关新闻

芯粒技术:半导体行业的成本与性能革命

芯粒技术:半导体行业的成本与性能革命

2026/7/28 10:17:31

1. 芯粒技术:半导体行业的范式革命当我在汽车电子实验室第一次拆解2024款智能汽车的域控制器时,一个指甲盖大小的模块引起了我的注意——这个集成了AI加速、传感器融合和通信功能的复杂系统,竟是由多个独立的小芯片像乐高积木一样拼接而成。这…

基于CH32x033的Arduino USB键盘开发:从环境搭建到HID设备实现

基于CH32x033的Arduino USB键盘开发:从环境搭建到HID设备实现

2026/7/28 10:17:31

1. 项目缘起:当Arduino遇上国产MCU的USB键盘梦最近在捣鼓一个桌面小工具,核心需求是想用一块小巧的开发板,通过USB接口模拟成一个键盘,自动执行一些按键序列,比如快速输入一串复杂的密码、或者一键打开某个软件组合。这…

智能回复系统构建指南:从NLP原理到工程部署实践

智能回复系统构建指南:从NLP原理到工程部署实践

2026/7/28 10:07:30

最近在社交媒体技术圈看到一个有趣的现象:Fable这个AI研究团队用8万条推文回应了用户的质疑。这背后其实反映了当前AI内容生成领域的一个重要趋势——大规模数据训练与用户反馈的闭环优化。本文将深入分析这一事件的技术背景,并手把手教你如何构建类似的…

【Bug已解决】[Bug]: DeepSeek-V4-Flash for L20,RuntimeError: Worker failed with error ‘AssertionError: aut

【Bug已解决】[Bug]: DeepSeek-V4-Flash for L20,RuntimeError: Worker failed with error ‘AssertionError: aut

2026/7/28 11:17:33

【Bug已解决】[Bug]: DeepSeek-V4-Flash for L20,RuntimeError: Worker failed with error AssertionError: auto_functionalized was not removed 解决方案 一、现象长什么样 在 L20(sm_89)上跑 DeepSeek-V4-Flash 时…

Java并发进阶系列:深度讨论高并发跳表数据结构ConcurrentSkipListMap的源代码实现(下)

Java并发进阶系列:深度讨论高并发跳表数据结构ConcurrentSkipListMap的源代码实现(下)

2026/7/28 11:17:33

文章说明:因为CSM解析内容较多,因此全文分为“深度讨论高并发跳表数据结构ConcurrentSkipListMap的源代码实现(上)”和“深度讨论高并发跳表数据结构ConcurrentSkipListMap的源代码实现(下)”两篇文章 上篇:CSM数据结构设计原理、doGet、doPut核心方法解析 下篇:doRemo…

Java并发进阶系列:深度讨论官方关于jdk1.8ConcurrentHashMap的computeIfAbsent源代码修复逻辑

Java并发进阶系列:深度讨论官方关于jdk1.8ConcurrentHashMap的computeIfAbsent源代码修复逻辑

2026/7/28 11:17:33

在文章中《深度解析官方关于jdk1.8的resizeStamp的bug处理过程》,我们讨论关于CHM的核心设计——resizeStam需要修复的处理过程,本文再次基于openJDK的bugs讨论组提出的CHM源代码另外一个会造成死循环的bug,默认读者已经掌握CHM的核心源代码实现,否则无法从本文的讨论中获益…

Java进阶系列:深度解析jdk1.8的HashMap红黑树balanceDeletion节点删除平衡算法设计(核心文章)

Java进阶系列:深度解析jdk1.8的HashMap红黑树balanceDeletion节点删除平衡算法设计(核心文章)

2026/7/28 11:17:33

这可能是全网最期待的jdk1.8的红黑树balanceDeletion的源代码解析技术文章! 其实掌握HashMap红黑树的同学都知道,balanceDeletion方法的源代码是HashMap红黑树部分最复杂也是最难理解的部分,目前少有coder对balanceDeletion有足够深入且可理解的分析,绝大部分关于深入Hash…

工业级负载控制方案:TPD2015FN与MKV42F128VLH16应用解析

工业级负载控制方案:TPD2015FN与MKV42F128VLH16应用解析

2026/7/28 11:17:33

1. 工业级负载控制方案概述在工业自动化、电力电子和高端设备控制领域,对电感和电阻负载的精确控制一直是工程师面临的核心挑战。TPD2015FN智能功率IC与MKV42F128VLH16微控制器的组合,为解决这一难题提供了可靠的技术方案。这套方案特别适用于需要高可靠…

物联网安全升级:SE050安全元件与TM4C1294NCPDT的完美结合

物联网安全升级:SE050安全元件与TM4C1294NCPDT的完美结合

2026/7/28 11:07:33

1. 物联网安全现状与SE050的定位在2023年的物联网安全态势报告中,全球每天新增的物联网设备达到惊人的150万台,但其中近70%的设备存在中高危安全漏洞。传统MCU方案(如STM32系列)虽然成本低廉,但在密钥存储、安全启动、…

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

2026/7/27 8:45:59

目标:电脑作为RTSP 服务端,循环推送 H264/H265 视频流; RDK X5 通过 rtsp2display 拉流预览,完全不需要在开发板编译 live555。 提供两套成熟方案: ✅ 方案 A:FFmpeg(最简单,优先推…

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

2026/7/27 8:42:17

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

2026/7/27 14:56:57

说实话,提到PDF拆分再压缩,我真是被折腾得够呛。 上个月公司年度合同归档,一份300多页的PDF总合同,需要按年份拆分成三个独立文件,再分别压缩到10MB以内方便邮件发送各部门确认。我心想这还不简单?先找个海…

零基础搭建桌面智能体,OpenClaw 2.7.9 分步实操,避开绝大多数部署陷阱

零基础搭建桌面智能体,OpenClaw 2.7.9 分步实操,避开绝大多数部署陷阱

2026/7/28 0:06:55

📌 一、工具核心优势盘点 数据本地存储,安全系数高所有操作日志、文档资料均保存在本机,不会上传至云端,能够有效保护企业文件与个人隐私,规避数据泄露风险。 上手简单,零编程门槛采用全图形化可视化界面&…

计算机毕业设计之基于springboot的购物平台设计与实现

计算机毕业设计之基于springboot的购物平台设计与实现

2026/7/28 0:06:55

由于移动应用技术的持续性的快速发展,现实生活中人们大多数都是通过移动手机、电脑等智能设备来完成生活中的事务。因此,许多的人工传统行业也开始与互联网结合,不再一味的依靠人工手动,努力打造半自动数字化甚至是全自动数字化模…

豆包AI绘图提示词失效真相:NLP模型层token截断机制首次披露,3招绕过字数限制

豆包AI绘图提示词失效真相:NLP模型层token截断机制首次披露,3招绕过字数限制

2026/7/28 0:06:55

更多请点击: https://codechina.net 第一章:豆包AI绘图提示词失效现象全景扫描 近期大量用户反馈,豆包(Doubao)AI绘图功能对常规提示词(Prompt)响应异常:语义明确的指令被忽略、中英…