╭(′▽`)╯

总之,我们都知道lca是啥,不需要任何基础也能想出来怎么用最暴力的方法求LCA,也就是深度深的点先跳到深度浅的点的同一深度,然后一起向上一步步跳。这样显然太慢了!

所以我们要用倍增,倍增比较屌,直接2^k速度往上跳,而且复杂度和树剖lca差不多,那么步骤分为两步

1.让两个点到同一深度

2.到了同一深度同步往上跳

反正我一开始看的时候一直在想,万一跳过了怎么办?哈哈哈,所以说我们有办法嘛:

定义deepv为v点的深度,设两个要求lca的点分别为a,b,且deepa >= deepb

所以,枚举找出最大的k使2^k <= deepa,这就是最大的跳的距离;

接着让他们到达同一深度:

从大到小枚举k,如果 deepa - 2^k >= deepb就往上跳2^k步,因为如果跳了2^k步的话一定deepa >= deepb

所以,我们跳的第一步一定是能跳的最大的一步,所以接下来只能跳次大的一步,同理跳完之后deepa >= deepb

......

因为k是越来越小的,k = 0的时候2^k = 1,因此无论如何最后都会以最大的效率跳到相同的深度

现在跳到了相同的深度,然后要同时向上走找到lca。

假设跳了 2 ^ k步之后它们到的位置不相等,说明lca还在深度更浅的地方,因为如果跳之后到的位置相等了,显然这个位置一定在lca的上面

所以,只要判断跳了 2 ^ k步后它们的位置如果不相等,就跳这步,这样就保证了跳到的深度一定小于lca,最后k = 0时 2 ^ k = 1,

则枚举完了k,它们所在的深度显然一定是lca的深度-1,则lca就是它们任意一个的父亲。

代码(luogu lca模板):

#include <cstdio>
#include <vector>
#include <cstring> const int MaxN = ; int n,m,s;
int par[MaxN][];
int deep[MaxN];
bool vis[MaxN]; struct Edge{
int to,nxt;
}e[MaxN*];
int head[MaxN];
int cnt; void add(int u,int v){
e[++cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
} void getdeep(int u){
vis[u] = ;
for(int i = head[u]; i; i = e[i].nxt){ int to = e[i].to;
if(to == u || vis[to]) continue; par[to][] = u; deep[to] = deep[u] + ; getdeep(to); } } void getpar(){
for(int up = ; (<<up) <= n; up++){
for(int i = ; i <= n ; i++){
par[i][up] = par[par[i][up-]][up-];
} } } int lca(int u,int v){
if(deep[u] < deep[v] ) std::swap(u,v); int max_jump = -; while(<<(max_jump+) <= deep[u]) max_jump++; for(int i = max_jump; i >= ; i--){
if(deep[u] - (<<i) >= deep[v]){
u = par[u][i];
} } if(u == v)
return u; for(int i = max_jump; i >= ; i--){
if(par[u][i] != par[v][i]){
u = par[u][i];
v = par[v][i]; }
} return par[u][]; return ; } int main()
{
scanf("%d%d%d",&n,&m,&s); for(int i = ; i < n; i++ ){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
//par[v][0] = u;
//par[u][0] = v;
} deep[s] = ; getdeep(s); getpar(); for(int i = ; i <= m; i++){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",lca(a,b)); } //par[i][j] = par[par[i][j-1]][j-1] return ;
}

【OI】倍增求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. Django项目:CRM(客户关系管理系统)--74--64PerfectCRM实现CRM课程排名详情

    #urls.py """PerfectCRM URL Configuration The `urlpatterns` list routes URLs to views. ...

  2. 爬虫的终极形态:nightmare

    爬虫的终极形态:nightmare nightmare 是一个基于 electron 的自动化库(意思是说它自带浏览器),用于实现爬虫或自动化测试.相较于传统的爬虫框架(scrapy/pyspider ...

  3. 阿里云应用高可用服务 AHAS 流控降级实现 SQL 自动防护功能

    在影响系统稳定性的各种因素中,慢 SQL 是相对比较致命的,可能会导致 CPU.LOAD 异常.系统资源耗尽.线上生产环境出现慢 SQL 往往有很多原因: 硬件问题.如网络速度慢,内存不足,I/O 吞 ...

  4. #queue队列 #生产者消费者模型

    #queue队列 #生产者消费者模型 #queue队列 #有顺序的容器 #程序解耦 #提高运行效率 #class queue.Queue(maxsize=0) #先入先出 #class queue.L ...

  5. HDU6187 Destroy Walls

        把这道题放了很久才来更新blog,似乎越来越懒了啊. 我们发现他给的城堡的坐标非常有趣啊,都是无理数. 对于其他所有点的坐标都是有理数的情况下,一个坐标为无理数的点绝对特别. 特别之处就是:经 ...

  6. html5绘图工具选择

    1. Chart.js 基于html5, 完全开源免费 功能过于简单,只有6种图,能满足小系统需求,使用简便,效果比较炫. http://www.bootcss.com/p/chart.js/ 2. ...

  7. ubuntu忘记root密码

    解决办法: 选择GRUB第2个选项(恢复模式) 按e进入编辑模式 将ro recovery nomodeset修改成rw single init=/bin/bash 然后再按F10进入单用户模式,进入 ...

  8. C#多线程之间事件通知

    我有两个线程,线程1接受网络数据,存到队列;线程2取队列,进行各种复杂的处理然后绘制到界面上;想让线程1有数据了通知线程2,线程2再取队列,因为不通知的话,线程2一直在while循环检索队列时候有东西 ...

  9. 公司-广告-WPP:WPP

    ylbtech-公司-广告-WPP:WPP WPP集团 (LSE:WPP) (NASDAQ:WPPGY),是世界上最大的传播集团,总部位于英国伦敦.WPP集团拥有 60 多个子公司,主要服务于本地.跨 ...

  10. svn清理以下路径失败

    网上说是svn的数据库挂了 删除里免得数据就好了 用sqllite...嗯? 那我还得下载一个?超过五秒钟的工作我是不会去做的 打开navicat 清空表 再次尝试清理