LCA模板 ( 最近公共祖先 )
LCA 有几种经典的求取方法、这里只给出模板,至于原理我完全不懂。
1、RMQ转LCA、复杂度O(n+nlog2n+m)
大致就是 DFS求出欧拉序 => 对欧拉序做ST表 => LCA(u, v) 即为 u、v 最先出现在欧拉序中的编号之间的最小值。
因为 LCA 的子树中必定有一个节点是 u,一个是 v,而且必定在两个节点到根节点的唯一路径上。
例如有欧拉序列 1 2 1 3 4 3 1 则 LCA(2, 3) == 1 、首次出现 2 的下标是 2、首次出现 3 的下标是 4、则 LCA 就是下标 2~4 之间的最小值即 1
#include<bits/stdc++.h> using namespace std; ;///顶点数 ]; int Head[maxn], cnt; int n, q, s;///点数、问询数、dfs起点 int fp[maxn]; int dfsLen;///每个顶点在欧拉序中第一次出现的位置、DFS序的长度(用做时间戳) int id[maxn]; int idLen;///每个顶点在DFS序中访问次序(用于离散化)、id数组的长度 ][];///跑ST表的dp数组(第二维应开到 ceil(log2(maxn<<1)) ) inline void init() { memset(dp, , sizeof(dp)); memset(Head, -, sizeof(Head)); cnt = ; idLen = dfsLen = ; } inline void AddEdge(int from, int to, int weight) { Edge[cnt].v = to; Edge[cnt].nxt = Head[from]; Head[from] = cnt++; } void dfs(int v, int Fa) { int tmp; id[tmp = ++idLen] = v; dp[fp[v] = ++dfsLen][] = tmp; ; i=Edge[i].nxt){ int Eiv = Edge[i].v; if(Eiv == Fa) continue; dfs(Eiv, v, d); dp[++dfsLen][] = tmp; } } void GetST() { ; (<<j)<=dfsLen; j++){ ; i+(<<j)-<=dfsLen; i++){ dp[i][j] = min(dp[i][j-], dp[i+(<<(j-))][j-]); } } } int LCA(int u, int v) { if(fp[u] > fp[v]) swap(u, v); int L = fp[u], R = fp[v]; )/log()); <<k)+][k])]; } int main(void) { scanf("%d %d %d", &n, &s, &q); ; i<n; i++){ int u, v; scanf("%d %d", &u, &v); AddEdge(u, v); AddEdge(v, u); } dfs(s, -); GetST(); while(q--){ int u, v; scanf("%d %d", &u, &v); printf("%d\n", LCA(u, v)); } ; }
2、树上倍增 、复杂度 O(n+nlog2maxDep+mlog2maxDep), maxDep在最坏情况下等于n
大致就是 DFS求出每个节点的深度、父亲节点这两个信息 => 通过倍增求出每个节点向根节点方向走 2^j 所能到达节点是什么
=> LCA(u, v) 就可以通过预先处理好的倍增数组先移动u、v使其深度一样、然后再一起 2^j 向上跳,直到跳转到 LCA
#include<bits/stdc++.h> using namespace std; ;///顶点的数目 ]; int Head[maxn], cnt; int dep[maxn], maxDep;///每个点的深度、最深点的深度 ];///倍增记录数组( Fa[i][j] 从 i 号节点开始走 2^j 步能到达的点 ) int n, m, s, q;///点、边、dfs起点、问询数 inline void init() { memset(Head, -, sizeof(Head)); memset(Fa, -, sizeof(Fa)); cnt = ; maxDep = ; } inline void AddEdge(int from, int to) { Edge[cnt].v = to; Edge[cnt].nxt = Head[from]; Head[from] = cnt++; } void dfs(int v) { ] != -) maxDep = max(maxDep, dep[v] = dep[Fa[v][]]+); ; i=Edge[i].nxt){ int Eiv = Edge[i].v; ]) continue; Fa[Eiv][] = v; dfs(Eiv); } } inline void Doubling() { )); ; j<=UP; j++){ ; i<=n; i++){ ] != -) Fa[i][j] = Fa[Fa[i][j-]][j-]; } } } int LCA(int u, int v) { )); if(dep[u] < dep[v]) swap(u, v); ; j--) && dep[Fa[u][j]] >= dep[v]) u = Fa[u][j]; if(u == v) return v; ; j--){ if(Fa[u][j] != Fa[v][j]){ u = Fa[u][j]; v = Fa[v][j]; } } ]; } int main(void) { scanf("%d %d %d", &n, &s, &q); ; i<n; i++){ int u, v; scanf("%d %d", &u, &v); AddEdge(u, v); AddEdge(v, u); } dfs(s); Doubling(); while(q--){ int u, v; scanf("%d %d", &u, &v); printf("%d\n", LCA(u, v)); } ; }
3、Tarjan算法( 离线 )、复杂度 O(n+m+nα(n))
大致就是 算了给个链接吧 Tarjan求LCA
#include<bits/stdc++.h> using namespace std; ; ]; struct Query{ int v, id; Query(){}; Query(int _v, int _id):v(_v),id(_id){}; }; vector<Query> q[maxn]; int Head[maxn], cnt; int Fa[maxn];///并查集数组 int ans[maxn];///问询数数组大小要注意一下、不一定是 maxn bool vis[maxn];///Tarjan算法中的标记数组 int n, m, s, qNum;///点、边、Tarjan递归起点、问询数 inline void init() { memset(Head, -, sizeof(Head)); memset(vis, false, sizeof(vis)); cnt = ; } inline void AddEdge(int from, int to) { Edge[cnt].v = to; Edge[cnt].nxt = Head[from]; Head[from] = cnt++; } int Findset(int x) { int root = x; while(Fa[root] != root) root = Fa[root]; int tmp; while(Fa[x] != root){ tmp = Fa[x]; Fa[x] = root; x = tmp; } return root; } void Tarjan(int v, int f) { Fa[v] = v; ; i=Edge[i].nxt){ int Eiv = Edge[i].v; if(Eiv == f) continue; Tarjan(Eiv, v); Fa[Findset(Eiv)] = v; } vis[v] = true; ; i<q[v].size(); i++){ if(vis[q[v][i].v]) ans[q[v][i].id] = Findset(q[v][i].v); } } int main(void) { init(); scanf("%d %d %d %d", &n, &m, &s, &qNum); ; i<=m; i++){ int u, v; scanf("%d %d", &u, &v); AddEdge(u, v); AddEdge(v, u); } ; i<q; i++){ int u, v; scanf("%d %d", &u, &v); q[u].push_back(Query(v, i)); q[v].push_back(Query(u, i)); } Tarjan(s, -); ; i<q; i++) printf("%d\n", ans[i]); ; }
4、树链剖分
并不会树剖,以后再补......
LCA模板 ( 最近公共祖先 )的更多相关文章
- HDU 2586 How far away ?(LCA模板 近期公共祖先啊)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the vi ...
- 【LCA求最近公共祖先+vector构图】Distance Queries
Distance Queries 时间限制: 1 Sec 内存限制: 128 MB 题目描述 约翰的奶牛们拒绝跑他的马拉松,因为她们悠闲的生活不能承受他选择的长长的赛道.因此他决心找一条更合理的赛道 ...
- CodeVs.2370 小机房的树 ( LCA 倍增 最近公共祖先)
CodeVs.2370 小机房的树 ( LCA 倍增 最近公共祖先) 题意分析 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天, ...
- 算法模板——LCA(最近公共祖先)
实现的功能如下——在一个N个点的无环图中,共有N-1条边,M个访问中每次询问两个点的距离 原理——既然N个点,N-1条边,则说明这是一棵树,而且联通.所以以1为根节点DFS建树,然后通过求两点的LCA ...
- [模板] 最近公共祖先/lca
简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...
- 【洛谷 p3379】模板-最近公共祖先(图论--倍增算法求LCA)
题目:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 解法:倍增. 1 #include<cstdio> 2 #include<cstdlib> 3 #include ...
- LCA——求解最近公共祖先
LCA 在有根树中,两个节点 u 和 v 的公共祖先中距离最近的那个被称为最近公共祖先(LCA,Lowest Common Ancestor). 有多种算法解决 LCA 或相关的问题. 基于二分搜索的 ...
- LCA(最近公共祖先)——离线 Tarjan 算法
tarjan算法的步骤是(当dfs到节点u时):1 在并查集中建立仅有u的集合,设置该集合的祖先为u1 对u的每个孩子v: 1.1 tarjan之 1.2 合并v到父节点u的集合,确保集合的祖 ...
- 倍增法求lca(最近公共祖先)
倍增法求lca(最近公共祖先) 基本上每篇博客都会有参考文章,一是弥补不足,二是这本身也是我学习过程中找到的觉得好的资料 思路: 大致上算法的思路是这样发展来的. 想到求两个结点的最小公共祖先,我们可 ...
随机推荐
- 【神经网络与深度学习】caffe静态链接库“Unknown layer type: Convolution (known types: )”和“ 磁盘空间不足”问题的解决办法
这一段时间把caffe在windows环境下编译了一下,tool里面的cpp全部编译成了exe.再用的时候有两个问题让我头疼了好长时间! 第一个问题 "db_lmdb.hpp:14] Che ...
- mysql——多表——合并查询结果
合并查询结果 合并查询结果 是将多个select语句的查询结果合并到一起 union关键字,数据库会将所有的查询结果合并到一起,然后除掉相同的记录: union all关键字,只是简单的合并到一起 前 ...
- BadUsb简单用法示例
所需硬件 badusb 自行淘宝 驱动程序会自动安装,若未自动安装自行百度 所需工具 arduino-1.5.5-r2用于编辑代码并上传至badusb badusb连接至电脑 打开ard ...
- etcd集群移除节点
查看当前集群信息 # etcdctl member list --write-out=table +------------------+---------+--------------------+ ...
- [转帖]Ubuntu 18.04 server安装图形界面及realvnc远程桌面连接
Ubuntu 18.04 server安装图形界面及realvnc远程桌面连接 https://blog.csdn.net/networken/article/details/88938304 转帖 ...
- volatile关键字?MESI协议?指令重排?内存屏障?这都是啥玩意
一.摘要 三级缓存,MESI缓存一致性协议,指令重排,内存屏障,JMM,volatile.单拿一个出来,想必大家对这些概念应该有一定了解.但是这些东西有什么必然的联系,或者他们之间究竟有什么前世今生想 ...
- mybatis一对一关联关系映射
mybatis一对一关联关系映射 在关联关系中,有一对一,一对多,多对多三种关联关系. 一对一关系:在操作上,任意一方引入对方的主键作为外键. 一对多关系:在"多"的一方添加&qu ...
- MySQL on duplicate key update 批量插入并更新已存在数据
业务上经常存在一种现象,需要批量往表中插入多条数据,但在执行过程中,很可能因为唯一键冲突,而导致批量插入失败.因此需要事先判断哪些数据是重复的,哪些是新增的.比较常用的处理方法就是找出已存在的数据,并 ...
- 机器学习-回归中的相关度和R平方值
1. 皮尔逊相关系数(Pearson Correlation Coefficient) 1.1 衡量两个值线性相关强度的量 1.2 取值范围[-1, 1] 正相关:>0, 负相关:<0, ...
- 解决错误:无法在web.xml或使用此应用程序部署的jar文件中解析绝对uri:[http://shiro.apache.org/tags]
服务器错误信息如下: 解决方法: 把shiro包中的tld文件(shiro.tld)解压出来放到WEB-INF文件夹下即解决问题. 参考:http://blog.sina.com.cn/s/blog_ ...