最近公共祖先问题(LCA)的几种实现方式
LCA也是很经典的内容了,我这个蒟蒻居然今天才开始弄QAQ
我太弱啦!
照例先上定义——————转自维基百科
在图论和计算机科学中,最近公共祖先是指在一个树或者有向无环图中同时拥有v和w作为后代的最深的节点。在这里,我们定义一个节点也是其自己的后代,因此如果v是w的后代,那么w就是v和w的最近公共祖先。
最近公共祖先是两个节点所有公共祖先中离根节点最远的,计算最近公共祖先和根节点的长度往往是有用的。比如为了计算树中两个节点v和w之间的距离,可以使用以下方法:分别计算由v到根节点和w到根节点的距离,两者之和减去最近公共祖先到根节点的距离的两倍即可得到v到w的距离。
下面蒟蒻就尝试总结几种求LCA的方式
1.倍增求LCA,优点:易于实现,理解难度不大
复杂度:预处理复杂度O(NlogN),查询复杂度O(logN)
2.ST表(RMQ)求lca,优点....可能是对于rmq学的好的人更容易理解?原谅蒟蒻rmq学的太烂qwq
复杂度:预处理O(NlogN)带一个常数,查询同样是O(logN)
3.tarjan求lca,优点是易于理解外加速度飞快,但他是离线算法,因此不适用于强制在线的题目
复杂度:O(N+M)
4.树链剖分求lca.....优点是所需空间很小...跑的也是飞快...
复杂度期望O(NlogN),但实际常数极小..理论上是最优的lca解法,
然而我不会啊orzzzzzzzzz
那么这篇博客主要就写一写倍增,基本能解决所有问题了
题目:
利用的是倍增 参考了yycc神犇的代码,%%%%%
#pragma GCC optimize("O2")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<limits.h>
#include<ctime>
#define N 100001
typedef long long ll;
const int inf=0x3fffffff;
const int maxn=2017;
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch>'9'|ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0')
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return f*x;
}
struct tsdl{
int w,to,next;
} edge[N*4];
int tot=0,head[500005],dp[500005][25],n,m,root,dep[500005];
void add(int ui,int vi)
{
edge[tot].next=head[ui];
edge[tot].to=vi;
head[ui]=tot++;
}
bool vis[500005];
void dfs(int x)
{
vis[x]=1;
for(int i=1;i<=20;i++)
{
if(dep[x]<(1<<i))break;//如果肯定跳不到,那么后面更不可能跳到,直接跳出
dp[x][i]=dp[dp[x][i-1]][i-1];//这句话是整个倍增算法的核心,也就是x的1<<i-1距离的祖先的1<<i-1距离的祖先是x的1<<i距离的祖先
}
for(int i=head[x];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(vis[v])continue;
dep[v]=dep[x]+1,dp[v][0]=x;//V的直接祖先是x
dfs(v);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(dep[y]<=dep[dp[x][i]])//如果可以跳,先跳一次
x=dp[x][i];
if(x==y)return x;//特判直接跳出
for(int i=20;i>=0;i--)
{
if(dp[x][i]!=dp[y][i])//只有在跳之后不同才跳
x=dp[x][i],y=dp[y][i];
}
if(x==y)return x;
if(dp[x][0]==0)return root;
return dp[x][0];//此时x的直接祖先即为答案
}
int main()
{
n=read(),m=read(),root=read();
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y),add(y,x);
}
dfs(root);
while(m--)
{
int x=read(),y=read();
printf("%d\n",lca(x,y));
}
}
最近公共祖先问题(LCA)的几种实现方式的更多相关文章
- 最近公共祖先:LCA及其用倍增实现 +POJ1986
Q:为什么我在有些地方看到的是最小公共祖先? A:最小公共祖先是LCA(Least Common Ancestor)的英文直译,最小公共祖先与最近公共祖先只是叫法不同. Q:什么是最近公共祖先(LCA ...
- 最近公共祖先问题 LCA
2018-03-10 18:04:55 在图论和计算机科学中,最近公共祖先,LCA(Lowest Common Ancestor)是指在一个树或者有向无环图中同时拥有v和w作为后代的最深的节点. 计算 ...
- 「LuoguP3379」 【模板】最近公共祖先(LCA)
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 最近公共祖先(LCA)学习笔记 | P3379 【模板】最近公共祖先(LCA)题解
研究了LCA,写篇笔记记录一下. 讲解使用例题 P3379 [模板]最近公共祖先(LCA). 什么是LCA 最近公共祖先简称 LCA(Lowest Common Ancestor).两个节点的最近公共 ...
- 洛谷P3379 【模板】最近公共祖先(LCA)
P3379 [模板]最近公共祖先(LCA) 152通过 532提交 题目提供者HansBug 标签 难度普及+/提高 提交 讨论 题解 最新讨论 为什么还是超时.... 倍增怎么70!!题解好像有 ...
- 洛谷 3379 最近公共祖先(LCA 倍增)
洛谷 3379 最近公共祖先(LCA 倍增) 题意分析 裸的板子题,但是注意这题n上限50w,我用的边表,所以要开到100w才能过,一开始re了两发,发现这个问题了. 代码总览 #include &l ...
- P3379 【模板】最近公共祖先(LCA)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- 洛谷P3379 【模板】最近公共祖先(LCA)(dfs序+倍增)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- 洛谷——P3379 【模板】最近公共祖先(LCA)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- luogo p3379 【模板】最近公共祖先(LCA)
[模板]最近公共祖先(LCA) 题意 给一个树,然后多次询问(a,b)的LCA 模板(主要参考一些大佬的模板) #include<bits/stdc++.h> //自己的2点:树的邻接链表 ...
随机推荐
- 记一次504 Gateway Time-out
使用curl请求是超时,查了下资料原来是端口被占用,造成了死锁,记录下 首先要知道为什么会出现死锁? 在我们访问页面的时候这个端口进程就已经被使用,当我们再在页面中curl请求其他页面因为没有其他的端 ...
- androidstudio上传代码到git上
1.首先通过git --bare init 在服务端创建好了一个git仓库:假设git仓库在服务端的地址为:/user/lyh/project/test.git 2.androidstudio上点击V ...
- wiki中文语料的word2vec模型构建
一.利用wiki中文语料进行word2vec模型构建 1)数据获取 到wiki官网下载中文语料,下载完成后会得到命名为zhwiki-latest-pages-articles.xml.bz2的文件,里 ...
- PageRank算法--从原理到实现
本文将介绍PageRank算法的相关内容,具体如下: 1.算法来源 2.算法原理 3.算法证明 4.PR值计算方法 4.1 幂迭代法 4.2 特征值法 4.3 代数法 5.算法实现 5.1 基于迭代法 ...
- clam简单使用
clam简单使用: 0,首先,要全局安装Nodejs,不再赘述.clam依赖node使用 1,打开 cmd 2,全局安装clam:npm -g install clam 3,切换到目的盘下,新建一个空 ...
- springBoot启动的时候动态选择装载某些bean
最近有这样一个场景,我们使用了elasticjob lite框架,希望某些job在指定服务器不启动.让spring动态的来装载所需要的job及相关bean 这个时候可以使用@Conditional家族 ...
- 写给自己看的新手java-环境配置
环境:win10. 第一步:下载jdk (类似于 net framework ) 环境运行库.地址:http://www.oracle.com/technetwork/java/javase/down ...
- 一文掌握 Linux 性能分析之 CPU 篇
本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 平常工作会涉及 ...
- Django组件-分页器
Django的分页器(paginator) view from django.shortcuts import render,HttpResponse # Create your views here ...
- unicode & utf-8
简单来说: Unicode 是「字符集」 UTF-8 是「编码规则」 其中: 字符集:为每一个「字符」分配一个唯一的 ID(学名为码位 / 码点 / Code Point) 编码规则:将「码位」转换为 ...