定义
LCA,最近公共祖先,是指一棵树上两个节点的深度最大的公共祖先。也可以理解为两个节点之间的路径上深度最小的点。
我们这里用了倍增的方法求了LCA。
我们的基本的思路就是,用dfs遍历求出所有点的深度。f[i][j]数组用来求的是距离节点i,距离2^j的祖先。可以知道,f[i][0]就是它的直接父亲。然后通过倍增的思路求出father数组的所有元素。然后进行lca。求lca的基本思路是:先让深度较大的点向上跳,
然后x和y再同时向上跳2的幂,总会跳到这样两个点,他们的父亲结点是同一个点,那就是x和y的LCA。

首先我们需要用邻接表建一颗参天大树~

重头戏——倍增。

int dep[maxn],f[maxn][];
/*dep数组用来记录当前点的深度
f[i][j]代表距离i 2^j的祖先
*/

深度和直接父亲:

void pre(int u,int fa)
{
dep[u]=dep[fa]+; //更新深度
f[u][]=fa;//更新父亲结点
for(int i=;(<<i)<=dep[u];i++){//预处理出f数组
f[u][i]=f[f[u][i-]][i-]; //这个转移可以说是算法的核心之一
//u的2^(i-1)级祖先的2^(i-1)级祖先就是u的2^i级祖先。
}
for(int i=head[u];i;i=e[i].next){//遍历邻接表
int to=e[i].to;
if(to==f[u][]) continue;//如果to是u的父亲,那么就说明这条边被访问过了,不能再回溯了
pre(to,u);//继续深度优先遍历
}
}

有的预处理工作都完成了。我们开始求LCA~

int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);//让x的深度更深
int cha=dep[x]-dep[y];//cha是x和y的深度之差
for(int i=;(<<i)<=cha;i++){
if((<<i)&cha){
x=f[x][i];
}
}//让x跳到跟y相同高度上
if(x!=y){//如果a和b不是同一个结点那么就要继续跳,如果是同一个结点,那么它就是LCA
for(int i=(int)log2(n);i>=;i--){//从大到小跳。正确性显然。
if(f[x][i]!=f[y][i]){//如果不相等,就说明该节点的深度还是比LCA大
x=f[x][i];
y=f[y][i];
//那就继续跳
}
}
x=f[x][];
//这个时候x和y还不是同一个节点,但是x和y的父亲就是x和y的lca。
}
return x;
}

常数优化:另外预处理出lg避免重复调用log函数

for(int i=;i<=n;i++)
lg[i]=lg[i-]+(<<lg[i-]==i);

P3379 【模板】最近公共祖先(LCA)

给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

对于100%的数据:N<=500000,M<=500000

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define num ch-'0'
#define rep(i,k,n) for(int i=k;i<=n;++i)
using namespace std;
int n,m,s,cnt=;
int head[],dep[],fa[][],lg[];
inline void get(int &res)
{
char ch;bool flag=;
while(!isdigit(ch=getchar()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getchar());res=res*+num);
(flag)&&(res=-res);
}
struct node
{
int to,nex;
}e[];
inline void add(int x,int y)
{
e[++cnt].nex=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void init(int u,int f)
{
dep[u]=dep[f]+;
fa[u][]=f;
for(int i=;(<<i)<=dep[u];++i)
fa[u][i]=fa[fa[u][i-]][i-];
for(int i=head[u];i;i=e[i].nex)
{
if(e[i].to==f) continue;
init(e[i].to,u);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y])
x=fa[x][lg[dep[x]-dep[y]]-];
if(x!=y)
{
for(int i=lg[dep[x]];i>=;--i)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
x=fa[x][];
}
return x;
}
int main()
{
get(n),get(m),get(s);
rep(i,,n-)
{
int x,y;
get(x),get(y);
add(x,y);add(y,x);
}
init(s,);
rep(i,,n) lg[i]=lg[i-]+(<<lg[i-]==i);
rep(i,,m)
{
int x,y;
get(x),get(y);
printf("%d\n",lca(x,y));
}
return ;
}

参考https://blog.csdn.net/qq_42386465/article/details/82978520

倍增求lca(模板)的更多相关文章

  1. 倍增求lca模板

    倍增求lca模板 https://www.luogu.org/problem/show?pid=3379 #include<cstdio> #include<iostream> ...

  2. 倍增求LCA学习笔记(洛谷 P3379 【模板】最近公共祖先(LCA))

    倍增求\(LCA\) 倍增基础 从字面意思理解,倍增就是"成倍增长". 一般地,此处的增长并非线性地翻倍,而是在预处理时处理长度为\(2^n(n\in \mathbb{N}^+)\ ...

  3. 树上倍增求LCA(最近公共祖先)

    前几天做faebdc学长出的模拟题,第三题最后要倍增来优化,在学长的讲解下,尝试的学习和编了一下倍增求LCA(我能说我其他方法也大会吗?..) 倍增求LCA: father[i][j]表示节点i往上跳 ...

  4. [算法]树上倍增求LCA

    LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 然后把深度更深的那一个点(4 ...

  5. 【倍增】洛谷P3379 倍增求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  6. hdu 2586 How far away ? 倍增求LCA

    倍增求LCA LCA函数返回(u,v)两点的最近公共祖先 #include <bits/stdc++.h> using namespace std; *; struct node { in ...

  7. 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)

    洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...

  8. 树链剖分与倍增求LCA

    树链剖分与倍增求\(LCA\) 首先我要吐槽机房的辣基供电情况,我之前写了一上午,马上就要完成的时候突然停电,然后\(GG\)成了送链剖分 其次,我没歧视\(tarjan LCA\) 1.倍增求\(L ...

  9. [学习笔记] 树上倍增求LCA

    倍增这种东西,听起来挺高级,其实功能还没有线段树强大.线段树支持修改.查询,而倍增却不能支持修改,但是代码比线段树简单得多,而且当倍增这种思想被应用到树上时,它的价值就跟坐火箭一样,噌噌噌地往上涨. ...

随机推荐

  1. Java-Runoob:Java 基础语法

    ylbtech-Java-Runoob:Java 基础语法 1.返回顶部 1. Java 基础语法 一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍 ...

  2. php对数组中的值进行排序

    案例 <?php $a = array('1124','1125','1126'); $s1 = 1124; $s2 = 1125; $ks1 = array_search($s1,$a); $ ...

  3. socket通讯实例与TCP/UDP的区别

    一.socket代码实例 1.简单的socket通讯: 服务端代码实例: import socket sock = socket.socket(socket.AF_INET, socket.SOCK_ ...

  4. Py修行路 python基础 (十二) 协程函数应用 列表生成式 生成器表达式

    一.知识点整理: 1.可迭代的:对象下有_iter_方法的都是可迭代的对象 迭代器:对象._iter_()得到的结果就是迭代器 迭代器的特性: 迭代器._next_() 取下一个值 优点: 1.提供了 ...

  5. Three.js响应和移动物体

    效果图 demo import './index.css'; // stats var stats; (function(){ stats = new Stats(); document.body.a ...

  6. 04.CSS的继承性和层叠性

    CSS有两大特性:  继承性和层叠性 继承性 面向对象语言都会存在继承的概念 , 在面向对象语言中, 继承的特点:  继承了父类的属性和方法.  那么 css  就是在设置属性的 ,  不会牵扯到方法 ...

  7. bash&nbsp;shell笔记1&nbsp;脚本基础知识

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://twentyfour.blog.51cto.com/945260/505644 * ...

  8. MySQL与SQLServer的update left join语法区别

    需求: 表A 字段 A_ID, A_NAME, B_ID 表B 字段 B_ID, B_NAME 需求把A的所有A_NAME更新为相应的B的 B_NAME. mysql做法: UPDATE A LEFT ...

  9. 游戏引擎架构Note2

    [游戏引擎架构Note2] 1.视觉属性(visual property)决定光线如何与物体表面产生交互作用. 2.一个Mesh所使用三角形的多少可以用细致程度(level-of-detail,LOD ...

  10. 【bzoj2190】[SDOI2008]仪仗队

    2190: [SDOI2008]仪仗队 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2638  Solved: 1674[Submit][Statu ...