LCA/在线(倍增)离线(Tarjan)
概念
祖先
有根树中,一个节点到根的路径上的所有节点被视为这个点的祖先,包括根和它本身
公共祖先
对于点a和b,如果c既是a的祖先又是b的祖先,那么c是a和b的公共祖先
##深度
子节点的深度=父节点深度+1,一般我们定根的深度为1
最近公共祖先
树上两个节点的所有公共祖先中,深度最大的那个称为两个点的最近公共祖先(LCA)
方法1:暴力爬山法
很明显,这个方法是很想爬山,我们可以先然两个节点中,深度大的依着父亲爬到两节点深度相同,然后,两个节点一起爬,最后,爬到了同一个节点,这,就是ans;

很明显,这个方法有几个缺陷,时间为O(n),并且,还要用bfs算深度
方法2:倍增
求公共祖先
在前面爬山法进行改进,在爬山的过程中,其实有些地方可以一蹦千尺高,但却一步一步地走,大大的浪费了时间,于是,我们运用倍增
众所周知,任意一个数是可用二进制来表示,如果,我们用一个二进制来表示两个节点的深度差,那不是就把时间化为O(log2n)
设一个数组dp[i][j]从i这个节点往上走2j步,那么,dp[i][j-1]j就是再往根的方向走2(j-1)步,如果再走2(j-1)步,就相当于走了2j,所以,dp[i][j]=dp[dp[i][j-1]][j-1]
其中,dp[i][0]=fa[i];
那如何来求dp这个数组呢
我们可以在bfs求树上每个点深度的时候,顺便预处理dp数组
void bfs()
{
queue<int>q;
d[root]=1;
q.push(root);
while(q.size())
{
int temp=q.front();
q.pop();
for(int i=0;i<g[temp].size();i++)
{
int v=g[temp][i];
if(d[v])
{
continue;
}
d[v]=d[temp]+1;
dp[v][0]=temp;
for(int j=1;j<=Maxstep;j++)
{
dp[v][j]=dp[dp[v][j-1]][j-1];
}
q.push(v);
}
}
}
LCA就是在爬山的基础上,将一步一步的枚举,改为,从大到小走2j
int LCA(int a, int b) {
if (d[a] > d[b]) {
swap(a, b);
}
for (int i = Maxstep; i >= 0; i--) {
if (d[dp[b][i]] >= d[a]) {
b = dp[b][i];
}
}
if (a == b) {
return a;
}
for (int i = Maxstep; i >= 0; i--) {
if (dp[b][i] != dp[a][i]) {
a = dp[a][i];
b = dp[b][i];
}
}
return dp[a][0];
}
求俩点的距离
可以先求出两点的LCA,然后,这两点的距离,就是公共祖先到A的距离+公共祖先到B的距离,而距离,可以和算深度一样,算到根节点的距离
int dist(int x, int y) { return d[x] + d[y] - d[LCA(x, y)] * 2; }
Tarjan
离线的求LCA的方法
先dfs,然后,标记,用并查集的路径压缩记录这个节点,最近的,没有回溯的节点,如果,询问的两个节点中有被访问的,那就可以将这个结点并查集的祖先放进去,正因为这样,所以,所有的,都需要先放进去,在dfs
void Trajan(int x) {
vis[x] = 1;
for (int i = 0; i < g[x].size(); i++) {
int v = g[x][i];
if (vis[v]) {
continue;
}
Trajan(v);
fa[v] = x;
}
for (int i = 0; i < q[x].size(); i++) {
int ID = q[x][i].id;
if (vis[q[x][i].v] == 1) {
ans[ID] = find(q[x][i].v);
}
}
}
LCA/在线(倍增)离线(Tarjan)的更多相关文章
- poj 1330 LCA (倍增+离线Tarjan)
/* 先来个倍增 */ #include<iostream> #include<cstring> #include<cstdio> #define maxn 100 ...
- hdu 2586 How far away?(LCA模板题+离线tarjan算法)
How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- POJ:1330-Nearest Common Ancestors(LCA在线、离线、优化算法)
传送门:http://poj.org/problem?id=1330 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K ...
- LCA 在线倍增法 求最近公共祖先
第一步:建树 这个就不说了 第二部:分为两步 分别是深度预处理和祖先DP预处理 DP预处理: int i,j; ;(<<j)<n;j++) ;i<n;++i) ) fa[i ...
- [POJ1330]Nearest Common Ancestors(LCA, 离线tarjan)
题目链接:http://poj.org/problem?id=1330 题意就是求一组最近公共祖先,昨晚学了离线tarjan,今天来实现一下. 个人感觉tarjan算法是利用了dfs序和节点深度的关系 ...
- 近期公共祖先(LCA)——离线Tarjan算法+并查集优化
一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...
- LCA在线算法ST算法
求LCA(近期公共祖先)的算法有好多,按在线和离线分为在线算法和离线算法. 离线算法有基于搜索的Tarjan算法较优,而在线算法则是基于dp的ST算法较优. 首先说一下ST算法. 这个算法是基于RMQ ...
- LCA在线算法(hdu2586)
hdu2586 How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/O ...
- LCA的倍增算法
LCA,即树上两点之间的公共祖先,求这样一个公共祖先有很多种方法: 暴力向上:O(n) 每次将深度大的点往上移动,直至二者相遇 树剖:O(logn) 在O(2n)预处理重链之后,每次就将深度大的沿重链 ...
随机推荐
- UNIX基本命令
### 1. 必学命令 help [子命令] : 查看某一个具体的子命令的使用方法### 2. 常用命令 - cd path : 将当前路径切换到path路径 - pwd : 查看当前所在路径 - l ...
- DT10功能介绍--DT10多波示波器
功能介绍 有些嵌入式软件方面的问题,利用传统的调试器可能无法解决,而通过逻辑分析器则能有效地解决.请仔细阅读本文, 看我们如何一步一步地讲解在这种情况下所需的配置. 但是,从传统意义上讲,逻辑分析器是 ...
- Apache APISIX 的安装和配置请求转发url匹配
安装apisix套件 创建一个apisix文件夹,在apisix文件夹下再创建一个etcd_data文件夹,用来持久化etcd的数据 在apisix文件夹下 新建3个文件 config.yaml, ...
- Python基础入门(5)- 函数的定义与使用
定义函数 函数的定义 函数的分类 函数的创建方法 函数的返回return 函数的定义 将一件事情的步骤封装在一起并得到最终结果 函数名代表了这个函数要做的事情 函数体是实现函数功能的流程 函数可以帮助 ...
- 基于Github Actions + Docker + Git 的devops方案实践教程
目录 为什么需要Devops 如何实践Devops 版本控制工具(Git) 学习使用 配置环境 源代码仓库 一台配置好环境的云服务器 SSH远程登录 在服务器上安装docker docker技术准备工 ...
- Nginx结构原理全解析
目录 一.Nginx简单介绍 二.Nginx优势 IO多路复用epoll模型 轻量级 Nginx的基本功能 .Nginx应用场景 Nginx代理 三.Nginx的结构解析 进程操作 事件模型 事件处理 ...
- 追踪工具strace
目录 一.简介 二.例子 找出程序读取的文件 查看现在程序在做什么 查看程序中哪个部分消耗大量cpu 无法连接服务器查看信息 一.简介 Linux 操作系统有很多用来跟踪程序行为的工具,内核态的函数调 ...
- Python测试框架pytest入门基础
Pytest简介 Pytest is a mature full-featured Python testing tool that helps you write better programs.T ...
- 扬我国威,来自清华的开源项目火爆Github
前几天TJ君跟大家分享了几个有趣的Github项目(加密解密.食谱.新冠序列,各种有趣的开源项目Github上都有),其中呢,有不少是来自斯坦福大学的项目,当时TJ君就不由得想,什么时候能看到的项目都 ...
- curl -w参数简析
curl的-w参数用于在一次完整且成功的操作后输出指定格式的内容到标准输出. 输出格式由普通字符串和任意数量的变量组成,输出变量需要按照%{variable_name}的格式,如果需要输出%,doub ...