思路

运用树上倍增法可以高效率地求出两点x,y的公共祖先LCA

我们设f[x][k]表示x的2k辈祖先

f[x][0]为x的父节点

因为从x向根节点走2k 可以看成从x走2k-1步 再走2k-1

所以对于1≤k≤logn 有f[x][k]=f[f[x][k-1]][k-1] (类似二分思想)

预处理:

因此我们可以对树进行遍历后得到所有f[x][0] 再计算出f数组的所有值

求LCA:

设dep[x]为x的深度 设dep[x]≥dep[y](否则 可以交换x和y)

使用二进制拆分 把x和y调整到同一深度

若此时x与y相等 则已经找到LCA

若不相等 则x和y同时向上跳同一深度 直到他们的父节点相同 则他们的父节点就是LCA

代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define maxn 500050
#define INF 1e9+7
int n,m,cnt,ans,a,b,k,x,y;
int h[maxn],dep[maxn],f[maxn][];
struct Edge
{
int next;
int to;
}e[maxn<<];
void add(int u,int v)
{
e[++cnt].to=v;
e[cnt].next=h[u];
h[u]=cnt;
}
void deal(int u,int fa)
{
dep[u]=dep[fa]+;//子节点深度等于父节点+1
for(int i=;i<=;i++)
{
f[u][i]=f[f[u][i-]][i-];//计算u的2^k辈祖先
}
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa) continue;//如果是父节点就退出
f[v][]=u;//v是u的子节点
deal(v,u);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);//如果x的深度比y小 就交换
for(int i=;i>=;i--)//从大到小循环 先走大步 如果不行在走小步
{
if(dep[f[x][i]]>=dep[y]) x=f[x][i];//当走完深度还是大于y 就走
if(x==y) return x;//当x=y时 找到LCA
}
for(int i=;i>=;i--)//此时x和y已经在同一层了
{
if(f[x][i]!=f[y][i])//如果往上走之后还没有到LCA 就往上走
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][];//返回LCA
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);//无向图
}
deal(,);//预处理
for(int i=;i<=m;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
}

【数据结构】浅谈倍增求LCA的更多相关文章

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

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

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

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

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

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

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

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

  5. 倍增求lca模板

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

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

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

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

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

  8. 树链剖分与倍增求LCA

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

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

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

随机推荐

  1. 六、Spring之DI的Bean的作用域

    Spring提供“singleton”和“prototype”两种基本作用域,另外提供“request”.“session”.“global session”三种web作用域:Spring还允许用户定 ...

  2. ES6,先知道这些必会的才行

    变量声明 const 和 let 不要用 var,而是用 const 和 let,分别表示常量和变量.不同于 var 的函数作用域,const 和 let 都是块级作用域. const DELAY = ...

  3. PAT 1038. Recover the Smallest Number

    #include <iostream> #include <cstdlib> #include <vector> #include <algorithm> ...

  4. 三大图表库:ECharts 、 BizCharts 和 G2,该如何选择?

    最近阿里正式开源的BizCharts图表库基于React技术栈,各个图表项皆采用了组件的形式,贴近React的使用特点.同时BizCharts基于G2进行封装,Bizcharts也继承了G2相关特性. ...

  5. nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)解决方案

    前提:已经配置好静态IP以防万一,先安装好iptables服务(不管你装没装,先执行,免得后面添乱)[root@localhost ~]# yum install iptables-services[ ...

  6. Raspberry U盘操作

    项目系统要求的对U盘分区,分出系统盘与用户盘.这就有了今天的这个总结了: 1.输入命令“fdisk -l”查看设备挂载的位置,因为这个在设备挂载的时候有可能会发生变化. 假设设备挂载到了 /dev/s ...

  7. DDMS 使用小结

    DDMS简介 DDMS功能详解 1 Devices面板 2 功能面板 3 LogCat and Console 1.DDMS简介 DDMS的全称是Dalvik Debug Monitor Servic ...

  8. Java基础之异常处理机制

    在Java中,异常分为编译时异常和运行时异常. 编译时异常又叫编译时被监测的异常:在程序编译过程中监测到非运行时异常的异常,出现该异常要么向上抛出,要么捕获处理.运行时异常(runtimeExcept ...

  9. freess(未测试)

    freess 使用 nodejs 配合 shadowsocks-windows 实现FQ (windows) 使用方法: 如果你没有安装nodejs请先安装,访问 https://nodejs.org ...

  10. git revert .vs. git reset .vs. git rebase

    1. git rervert的工作方式是:将一个老的commit的改动完全找出来,并且在新的tip处运行反操作,最终清除老commit的改动: git revert的应用场景多在对public rep ...