首页 > 编程语言 >(未完)【算法学习笔记】04 最近公共祖先LCA

(未完)【算法学习笔记】04 最近公共祖先LCA

时间:2022-08-15 00:16:16浏览次数:57  
标签:04 int depth fa 算法 dx LCA root

【算法学习笔记】04 最近公共祖先LCA

原理

顾名思义,就是求两点的最近公共祖先(自己也是自己的祖先)。
也就是两点在走到根节点的路径上最先遇到的共同的点。

向上标记法

比较贴定义的原始方法。
一点先向 \(root\) 走,走过的点标记一下;然后另一点也往 \(root\) 走,走到的第一个被标记的点为二者的 \(LCA\)。时间复杂度为 \(O(n)\)

倍增法

1. 首先需要记录两个变量

1. \(f(i, j)\)

表示从 \(i\) 开始,向上走 \(2^j\) 步能到达的节点,\(0\leq j\leq logn\)
那么怎么更新?

  1. \(j=0\), \(f(i,j)\) 为 \(i\) 的父节点
  2. \(j>0\), \(f(i,j)=f(f_(i,j-1),j-1)\),相当于跳了两个 \(2^{j-1}\)
    这一过程可用 \(bfs/dfs\) 求
2. \(depth(i)\)

表示 \(i\) 的深度

哨兵

\(depth(0)=0\)
如果从 \(i\) 开始跳 \(2^j\) 步会跳过根节点,那么 \(f(i,j)=0\)。

2. 将两点跳到同一层

具体操作如下:
相当于用我们之前处理好的二进制数来拼凑 \(dx = |depth(x)-depth(y)|\),即从后往前找到第一个满足 \(2^k \leq dx\) 的 \(k\), 然后令 \(dx -= 2^k\), 重复这个找的过程,直至 \(dx=0\)。
的过程不用算具体值,只需判断是否满足 \(depth(f(x,k))\geq depth(y)\)即可。

3. 让两个点一直往上跳,直到跳到 \(LCA\) 的下一层(儿子那层)

为什么要到下一层?
因为到本层(\(LCA\))时无法判断是否为 \(LCA\),为避免歧义才到下一层。
跳的过程也是二进制拼凑,从大到小枚举 \(k\), 直至 \(f(a,k)=f(b,k)\), 此时到了点\(x, y\),在往上一层,也就是他们的父亲就是 \(LCA\),即 \(LCA=f(x,0)=f(y,0)\)。

板子

先贴一个y总的板子来吓吓我的vsc,明天来自己写一遍


void bfs(int root)
{
    memset(depth, 0x3f, sizeof depth);
    depth[0] = 0, depth[root] = 1;
    int hh = 0, tt = 0;
    q[0] = root;
    while (hh <= tt)
    {
        int t = q[hh ++ ];
        for (int i = h[t]; ~i; i = ne[i])
        {
            int j = e[i];
            if (depth[j] > depth[t] + 1)
            {
                depth[j] = depth[t] + 1;
                q[ ++ tt] = j;
                fa[j][0] = t;
                for (int k = 1; k <= 15; k ++ )
                    fa[j][k] = fa[fa[j][k - 1]][k - 1];
            }
        }
    }
}

int lca(int a, int b)
{
    if (depth[a] < depth[b]) swap(a, b);
    for (int k = 15; k >= 0; k -- )
        if (depth[fa[a][k]] >= depth[b])
            a = fa[a][k];
    if (a == b) return a;
    for (int k = 15; k >= 0; k -- )
        if (fa[a][k] != fa[b][k])
        {
            a = fa[a][k];
            b = fa[b][k];
        }
    return fa[a][0];
}

离线的做法也没学
还没写题呢,明天一定(

标签:04,int,depth,fa,算法,dx,LCA,root
From: https://www.cnblogs.com/CTing/p/16586716.html

相关文章

  • LCA 相关 && 树链剖分
    LCA基本定义:最近公共祖先简称LCA(LowestCommonAncestor)。两个结点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个。简单来讲,就是两个点到根的路径上,深度最深......
  • 详解二分查找算法 && leetcode35. 搜索插入位置
    https://blog.csdn.net/weixin_39126199/article/details/118785065 https://leetcode.cn/problems/search-insert-position/classSolution{public:intsearc......
  • ISP开源算法
      awesome-ISP https://github.com/starkfan007/awesome-ISP ExamplesopenISP--OpenImageSignalProcessor [code]fast-openISP--FastOpenImageSigna......
  • P1190 [NOIP2010 普及组] 接水问题(嵌套循环——贪心算法)
    学校里有一个水房,水房里一共装有mm个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为11。现在有nn名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺......
  • 404和路由钩子
    获取登录后username信息this.$router.push("/main/"+this.form.username);/main后加/+传递的username(传入参数)  index.js路由中path写入参数:name,并将props设为tru......
  • Java学习 (20) Java数组篇(04)Arrays类&冒泡排序&稀疏数组
    目录Arrays类语法实例冒泡排序语法实例具体讲解视频(狂神说Java)稀疏数组语法实例具体讲解视频(狂神说Java)Arrays类教组的工具类java.util.Arrays由于数组对象本身并没有......
  • 道长的算法笔记:经典哈希表问题
    (一)哈希表简述Waiting...(二)使用哈希表优化复杂度(2.1)两数之和Waiting...(2.2)子数组异或和#include<bits/stdc++.h>#include<algorithm>usingnamespace......
  • python | 算法大神左神(左程云)算法课程 第三节
    基数排序-python版视频笔记戳这里#基数排序#针对非负数排序classradixSort():defradixSortAll(self,arr):"""对数组arr进行基数排序......
  • YbtOJ 「基础算法」第3章 二分算法
    例题1.数列分段二分每段和的最大值。check时从左往右扫,如果当前段的和大于限制则新开一段。code#include<bits/stdc++.h>usingnamespacestd;constintN=1e5+5;i......
  • Ubuntu 20.04 配置静态IP地址
    vim/etc/netplan/00-installer-config.yaml#Thisisthenetworkconfigwrittenby'subiquity'network:ethernets:ens160:dhcp4:noaddresse......