╭(′▽`)╯

总之,我们都知道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. Linux 内存缓存占用过大,Centos7设置定时清除buff/cache的脚本

    Linux系统buff/cache 中缓存数据占用内存过高,定时清理buff/cache ,释放系统内存 root权限创建脚本文件: touch cleanCache.sh && vi ...

  2. PLSQL直接通过客户端连接远程

  3. IO流16 --- 对象流操作字符串 --- 技术搬运工(尚硅谷)

    序列化 @Test public void test12() throws IOException { ObjectOutputStream oos = new ObjectOutputStream( ...

  4. python运~算~~符!!!!!!!!!!!

    目录: 算术运算, 用于加减乘除等数学运算 赋值运算,用于接收运算符或方法调用返回的结果 比较运算, 用于做大小或等值比较运算 逻辑运算,用于做 与.或.非运算 位运算, 用于二进制运算 每种运算中所 ...

  5. 设置div背景图片填满div

    可以设置div的样式为 background:url('+UPLOAD_PATH+data.url+') no-repeat; background-size: 100%;width:100%;hei ...

  6. LOJ 6042 跳蚤王国的宰相

    LOJ 6042 跳蚤王国的宰相 题意 跳蚤王国爆发了一场动乱,国王在镇压动乱的同时,需要在跳蚤国地方钦定一个人来做宰相. 由于当时形势的复杂性,很多跳蚤都并不想去做一个傀儡宰相,带着宰相的帽子,最后 ...

  7. python \r \t \n 各种转义字符

    转义字符 描述 \(在行尾时) 续行符 \\ 反斜杠符号 \’ 单引号 \” 双引号 \a 响铃 \b 退格(Backspace) \e 转义 \000 空 \n 换行 \v 纵向制表符 \t 横向制 ...

  8. 2019阿里云开年Hi购季必抢!爆爆爆爆爆爆爆款清单来了!

    摘要: 鸡冻人心的三月开年Hi购季来了,根本不知道该买哪款?这次就给大家列一波口碑爆款! 鸡冻人心的三月开年Hi购季来了 个个摩拳擦掌 为了算清楚能省多少钱 颓废多年的数学水平 仿佛在这个节日回到了高 ...

  9. 【html、CSS、javascript-5】css应用场景补充

    一.CSS全局应用 父标签div下包含两个子标签div,当子标签dvi全部向左float,此时父标签设置的背景色是不显示的 <!DOCTYPE html> <html lang=&q ...

  10. ConcurrentDictionary让你的多线程代码更优美

    ConcurrentDictionary是.net4.0推出的一套线程安全集合里的其中一个,和它一起被发行的还有ConcurrentStack,ConcurrentQueue等类型,它们的单线程版本( ...