最近公共祖先问题(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点:树的邻接链表 ...
随机推荐
- Memcached操作
标准协议和字段 Memcached的标准协议字段包含以下部分: 键,key,任意字符,最大250字节,不能有空格和换行 标志位,32比特,不能为0 超时时间,单位是秒,0代表永不超时,最长30天,30 ...
- IIS虚拟目录内的视频文件访问出错:HTTP 错误 404.3 - Not Found 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。
MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开.多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式. 我是 ...
- C++: sprintf浮点数精度控制;
错误的写法: char buf[100]; int num = 10; sprintf(buf, "%.2f", num); ///这种做法是不对的, 按照压栈顺序, 在压入num ...
- JDK1.8 HashMap源码分析
一.HashMap概述 在JDK1.8之前,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时 ...
- C++回顾day02---<继承相关问题>
一:继承和组合混搭时,构造和析构调用原则 (一)先构造父类,再构造成员变量,最后构造自己 (二)先析构自己,再析构成员变量,最后父类析构(方向与构造相反) class A { public: int ...
- MySQL安全配置向导mysql_secure_installation详解
安装完mysql-server 会提示可以运行mysql_secure_installation.运行mysql_secure_installation会执行几个设置: a)为root用户设置密码 ...
- ES6 数组遍历方法的实战用法总结(forEach,every,some,map,filter,reduce,reduceRight,indexOf,lastIndexOf)
目录 forEach every some map filter reduce && reduceRight indexOf lastIndexOf 前言 ES6原生语法中提供了非常多 ...
- android studio发布项目到github
点击file setting ,打开对话框,如下,判断git是否安装成功 选择GitHub,填写github地址及密码 发布项目:
- keepalive半同步双主一从
ip地址如下: 192.168.20.201 redis01 主 192.168.20.202 redis02 主 192.168.20.203 redis03 从 192.168.20.205 vi ...
- Ubuntu18.04更换国内源(阿里,网易,中科大,清华等源)
1.备份 备份/etc/apt/sources.list文件 mv /etc/apt/sources.list /etc/apt/sourses.list.backup 2.新建 新建/etc/apt ...