博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
倍增求LCA学习笔记(洛谷 P3379 【模板】最近公共祖先(LCA))
阅读量:6357 次
发布时间:2019-06-23

本文共 1877 字,大约阅读时间需要 6 分钟。

倍增求\(LCA\)

倍增基础

从字面意思理解,倍增就是“成倍增长”。

一般地,此处的增长并非线性地翻倍,而是在预处理时处理长度为\(2^n(n\in \mathbb{N}^+)\)的区间值。在这些预处理结果的基础上,我们可以进一步求出任意长度区间的答案。

比如区间最值问题\((RMQ)\)就可以使用倍增解决。对于每个起始点,预处理长度为\(2^n\)的区间最值。之后每段区间都可以以此求出,如:

\(f(1,7)=\max(f(1,4),f(3,7))\)

以上是最简单的一个举例。在计算机中,二进制的思想运用广泛。它能将复杂度中\(n\)因子化为\(log_2n\),还可以使用位运算进行常数优化。

\(LCA\)

LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。——百度百科

定义很好理解。朴素的做法是预处理深度,将深度大的向上跳,再一起向上跳直到相遇。复杂度不好算,但绝对T飞。

注意到当两点相遇后,再如何跳都在同一个点上。所以就相当于\(LCA\)下不同,\(LCA\)上相同。这具有单调性,考虑二分。此处要对每一个点存储\(2^n\)级祖先,方法是预处理时递推。

我们记点i的\(2^k\)级祖先为\(fa[i][k]\)

求解\(LCA\)的过程分为两步:一是提升到同一高度,二是同时向上跳。从最大的\(fa[x][log_2(depth[x])]\)开始逐次减半,相同则不跳,不同则跳。最终会到达\(LCA\)的下方。此时返回其中一个点的父亲,算法结束。

另外,预处理\(log_2\)的结果可以优化常数。

代码

#include
#include
#include
using namespace std;int n,m,s,x,y;const int MAXN=500005;struct edge{ int to,next;}tree[MAXN*2];int depth[MAXN],lg2[MAXN],head[MAXN],fa[MAXN][25],eg,temp;int add(int from,int to){ tree[++eg].to=to; tree[eg].next=head[from]; head[from]=eg;}int get_depth(int node,int father)//当前点和父亲{ depth[node]=depth[father]+1; fa[node][0]=father; for(int i=1;i<=lg2[depth[node]]-1;i++) fa[node][i]=fa[fa[node][i-1]][i-1];//node的2^i级父亲等于它的 2^(i-1)级父亲的2^(i-1)级父亲 for(int i=head[node];i;i=tree[i].next) if(tree[i].to!=father) get_depth(tree[i].to,node);}inline int LCA(int x,int y){ if(depth[x]
depth[y]) x=fa[x][lg2[depth[x]-depth[y]]-1];//跳到相同高度 if(x==y) return x; for(int i=lg2[depth[x]]-1;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0];//注意返回的不是x,是x的父亲}int main(){ scanf("%d %d %d",&n,&m,&s); for(int i=1;i<=n-1;i++) scanf("%d %d",&x,&y),add(x,y),add(y,x);//建树 for(int i=1;i<=MAXN;i++) lg2[i]=lg2[i-1]+(1<

转载于:https://www.cnblogs.com/ehznehc/p/11033241.html

你可能感兴趣的文章
在html 的img属性里只显示图片的部分区域(矩形,给出开始点和结束点),其他部份不显示,也不要拉伸...
查看>>
程序员第二定律:量化管理在程序员身上永无可能
查看>>
ubuntu一些脚本的执行顺序
查看>>
类继承的结构
查看>>
Intel 被 ARM 逼急了
查看>>
testng + reportng 测试结果邮件发送
查看>>
百度亮相iDASH,推动隐私保护在人类基因组分析领域的应用
查看>>
Python「八宗罪」
查看>>
你的隐私还安全吗?社交网络中浏览历史的去匿名化
查看>>
NeurIPS 2018|如何用循环关系网络解决数独类关系推理任务?
查看>>
Windows 10 份额突破 40%,Windows 7 连跌四月终回升
查看>>
怎么把Maven项目转为动态Web项目?
查看>>
Arm发布Cortex-A76AE自动驾驶芯片架构,宣示车载系统市场主权
查看>>
Hibernate入门教程
查看>>
Java支付宝扫码支付[新]
查看>>
SpringMVC 拦截器 筛选
查看>>
第十八章:MVVM(八)
查看>>
点击表头切换升降序排序方式
查看>>
第26天,Django之include本质
查看>>
Java中静态变量和实例变量的区别
查看>>