树如何找共同祖先_树的运用:求树上共同祖先LCA
注:求解LCA有至少7种做法,如果让我全部写出来,我会死掉的。这里我只讲朴素和倍增
注:抄别人的代码不是一个好习惯 我不会告诉你这个代码我可以弄了一点点失误进去
版权声明:倍增代码使用的是李白莘莘学子的代码,原文点这里
下面列举一下LCA的做法:朴素算法,倍增,RMQ,用欧拉序列转化为RMQ ,太监(tarjan)和动态树(看这里有惊喜)
RMQ以后将分块时可能会去提(前提我记得)(180+行),太监其中有dfs序和邻接链表,不讲(90+行)。树剖以后讲到会提(很快就讲)
//朴素算法
#include
#define MAXN 100100
using namespace std
int n,head[MAXN],dep[MAXN],cnt=0,q,fa[MAXN];
struct edge
{
int nxt,to;
}e[MAXN];
void add(int u,int v)
{
e[++cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dep_ccl(int u,int f)//预处理fa[]数组及深度
{
dep[u]=dep[f]+1;//原点深度等于他爸的深度加一
fa[u]=f;
for(int i=head[u];i!=0;i=e[i].nxt)//基操遍历
{
int v=e[i].to;
if(v!=f)dep_ccl(v,u);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
dfs(1,0);
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
ans=0;
int a,b;
scanf("%d%d",&a,&b);
while(a!=b)//LCA
{
if(dep[a]>=dep[b])a=fa[a];
else b=fa[b];
}
cout<
}
return 0;
}
//倍增
#include//万能头
#define MAXN 200200
using namespace std;
int n,m,s,cnt=0,head[MAXN],dep[MAXN],f[MAXN][23];
int a,a;
struct edge{
int next,to;
}e[4*MAXN]
void e_add(int u,int v)//链式前向星存图
{
cnt++;
e[cnt].next=head[u];e[cnt].to=v;head[u]=cnt;
e[++cnt].next=head[v];e[cnt].to=u;head[v]=cnt;
}
void dfs(int u,int father)//对应深搜预处理f数组
{
dep[u]=dep[father]+1;
for(int i=1;(1<
{
f[u][i]=f[f[u][i-1]][i-1];
}
for(int i=head[u];i;i=e[i].next)//遍历树
{
int v=e[i].to;
if(v==father)continue;//双向图需要判断是不是父亲节点
f[v][0]=u;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(dep[x]
for(int i=20;i>=0;i--)//从大到小枚举使x和y到了同一层
{
if(dep[f[x][i]]>=dep[y])x=f[x][i];
if(x==y)return x;
}
for(int i=20;i>=0;i--)//从大到小枚举
{
if(f[x][i]!=f[y][i])//尽可能接近
{
x=f[x][i];y=f[y][i];
}
}
return f[x][0];//f[y][0]也ok
}
int main(){
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i
{
scanf("%d",&a1);scanf("%d",&a2);
e_add(a1,a2);//链式前向星存图
}
dfs(s,0);//预处理
for(int i=1;i<=m;i++)
{
scanf("%d %d",&a1,&a2);
printf("%d\n",lca(a1,a2));//求两个节点的LCA
}
}
首先,是我们的朴素算法O(n^2)。
首先,将树上每个节点的深度预处理出来,还有他们的霸霸预处理出来。
方法:爆搜。开两个函数变量:u(遍历到的节点)和f(u他爸)。将整棵树遍历一遍。
遍历过程中,将fa[u](即u他的fuqin节点)赋值为f,dep[u](即u的深度)赋值为dep[f]+1(即u他爸的深度,以前遍历出来过)
然后在主函数中,定义两个指针a,b,最开始的时候指向要求LCA的那两个点。
每次让更深的那个指针往上跳一个点。即a=fa[a]||b=fa[b]
然后在两指针指向同一个点时,这个点就是他们的LCA,原因你自己想想。这不是废话吗
倍增,就是在朴素算法的基础上,呈倍 增上去。同样,有一个fa数组,需要预处理出来。
其中fa[i][j]表示i的第\(2^j\)个祖先。利用fa的定义(即fa[i][j]表示i的第\(2^j\)个祖先)用循环预处理出fa数组。
其中有个地方做一点点解释
for(int i=20;i>=0;i--)//从大到小枚举使x和y到了同一层
{
if(dep[f[x][i]]>=dep[y])x=f[x][i];
if(x==y)return x;
}
for(int i=20;i>=0;i--)//从大到小枚举
{
if(f[x][i]!=f[y][i])//尽可能接近
{
x=f[x][i];y=f[y][i];
}
}
这里i为什么是20到1呢?先看代码
我们发现f的第二位的下标都是i,意味着一定是求某个数的\(2^i\)个祖先。
如果你担心,你尽可以开31->1甚至63->1,不过一般题目不会给那么大的数据,一般是2^20左右的,这就是这样来的。
树如何找共同祖先_树的运用:求树上共同祖先LCA相关推荐
- 最近公共祖先_[LeetCode] 236. 二叉树的最近公共祖先
题目链接: https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree 难度:中等 通过率:57.2% 题目描述: ...
- java并查集找朋友圈_并查集求朋友圈最大人数
#include #include using namespace std ; int findRoot( int set[ ], int s ) { if (s == set[s]) return ...
- 字典树哇 AC自动机哇 = _ =
字典树哇 AC自动机哇 = _ = 例题 HDU 1251 统计难题 解题思路 : 字典树 原理:按照每个根向下发散 形成一棵 树 这个题 需要在每一个字母处都做统计 (求前缀单词) 开一个 二维数组 ...
- java二叉树是什么_树的基本概念以及java实现二叉树
树具有的特点有: (1)每个结点有零个或多个子结点 (2)没有父节点的结点称为根节点 (3)每一个非根结点有且只有一个父节点 (4)除了根结点外,每个子结点可以分为多个不相交的子树. 树的基本术语有: ...
- 3层b+树索引访问磁盘次数_【112期】面试官:为什么选择B+树作为数据库索引结构?谈谈你的理解
本文同步Java知音社区,专注于Java 阶段汇总集合:++小Flag实现,一百期面试题汇总++ 背景 首先,来谈谈B树.为什么要使用B树?我们需要明白以下两个事实: [事实1] 不同容量的存储器,访 ...
- 二叉树第i层中的所有结点_讲透学烂二叉树(二):图中树的定义amp;各类型树的特征分析...
日常中我们见到的二叉树应用有,Java集合中的TreeSet和TreeMap,C++ STL中的set.map,以及Linux虚拟内存的管理,以及B-Tree,B+-Tree在文件系统,都是通过红黑树 ...
- 高度为5的3阶b树含有的关键字个数_第15期:索引设计(索引组织方式 B+ 树)
谈到索引,大家并不陌生.索引本身是一种数据结构,存在的目的主要是为了缩短数据检索的时间,最大程度减少磁盘 IO. 任何有数据的场景几乎都有索引,比如手机通讯录.文件系统(ext4xfsntfs).数据 ...
- 【数据结构】_树与二叉树
目录 引言 一.什么是树? 1.树的定义 2.树的特点 3.树的表示法 二.树的一些基本术语 三.树的性质 四.什么是二叉树? 1.基本概念 2.二叉树的五种基本形态 3.二叉树的性质 五.满二叉树. ...
- 编译原理学习笔记(二十九)~习题:分析句子 id--id*id的 最右推导过程,画出分析树,找出和分析过程中每一步的对应关系。
题目 分析句子 id–id*id的 最右推导过程,画出分析树,找出和分析过程中每一步的对应关系. 语法如下: E → E - T (1) E → T (2) T → T * F (3) T → F(4 ...
最新文章
- python -- IO多路复用
- SpringBoot - 实践阿里巴巴【Manager 层_通用业务处理层】
- 我本人一直以来犯的错误,在看了 Think In Java 后才抓了出来
- dedecms 常用标签
- 用自定义函数联合IF函数实现“一对多”查询
- 拼多多开除即将拿到股票的安全大佬;虾米音乐将永久关停;GitHub 解禁伊朗开发者使用权
- h5球的立体效果_使用HTML5 Canvas 2D直角坐标系实现三维球体效果
- Linux 下 4 种实时监控日志文件的方法,你都会用吗?
- 同步手绘板——关于/dev/graphics/fb0权限的获取
- 卸载Symantec——无需密码,卸载干净,Windows
- html5禁用浏览器下拉,禁止ios浏览器页面上下滚动 (橡皮筋效果)
- C/C++之奔跑的小人(小游戏,自娱自乐)
- android读取wlan信息,Android判断Wlan信号强弱及wlan管理信息
- 分享一个优雅的vi配置
- [stanford NLP] 原理小结
- 入手评测 联想小新Pro16和thinkbook15p有什么区别 选哪个
- REST Assured 17 - 设置默认的RequestSpecification
- 系统信息:uname,sysinfo,gethostname,sysconf
- 【饭谈】软素质怎么提高?(适合软件测试人的专用办法)
- 转计算机网络应用申请书,转专业相关申请书最新6篇