【算法】树上倍增 & LCA

文章目录

相关链接

把相关链接放在最前面是因为,周赛遇到了几次,不会做。这才想起来学一下这个算法。

【力扣周赛】第 360 场周赛(⭐树上倍增)
【力扣周赛】第 361 场周赛(⭐树上倍增、LCA)

模板题目

1483. 树节点的第 K 个祖先

https://leetcode.cn/problems/kth-ancestor-of-a-tree-node/description/

提示:

1 <= k <= n <= 5 * 10^4
parent[0] == -1 表示编号为 0 的节点是根节点。
对于所有的 0 < i < n ,0 <= parent[i] < n 总成立
0 <= node < n
至多查询 5 * 10^4 次

java 复制代码
class TreeAncestor {
    int[][] pa;

    // 使用原始数据将整个 pa 数组预处理出来
    public TreeAncestor(int n, int[] parent) {
        int m = 32 - Integer.numberOfLeadingZeros(n);   // n的二进制长度
        pa = new int[n][m];                 // 表示节点i的2^j个祖宗节点
        // 初始化dp数组,即填充每个节点的父亲节点
        for (int i = 0; i < n; ++i) {
            pa[i][0] = parent[i];
        }
        // 先枚举i,再枚举x
        // 相当于先算出所有爷爷节点,再算出所有爷爷的爷爷节点
        for (int i = 0; i < m - 1; i++) {
            for (int x = 0; x < n; ++x) {
                int p = pa[x][i];   // 取出x的第2^i个祖宗节点
                // x的第2^(i+1)个祖宗节点 等于 x的第2^i个祖宗节点的第2^i个祖宗节点
                pa[x][i + 1] = p < 0? -1: pa[p][i]; 
            }
        }
    }
    
    // 取出node节点的第k个祖宗节点
    public int getKthAncestor(int node, int k) {
        // 写法1 从低位到高位枚举
        // int m = 32 - Integer.numberOfLeadingZeros(k);   // k的二进制长度
        // for (int i = 0; i < m; ++i) {
        //     if ((k >> i & 1) == 1) {        // k的二进制当前位为1
        //         node = pa[node][i];
        //         if (node < 0) break;
        //     }
        // }
        // return node;

        // 写法2 不断去掉k末尾的1
        for (; k != 0 && node != -1; k &= k - 1) {
            node = pa[node][Integer.numberOfTrailingZeros(k)];
        }
        return node;
    }   
}

/**
 * Your TreeAncestor object will be instantiated and called as such:
 * TreeAncestor obj = new TreeAncestor(n, parent);
 * int param_1 = obj.getKthAncestor(node,k);
 */

最近公共祖先LCA的求法

两个节点 x 和 y,

先将 x 和 y 放在同一个深度上,即先让 y 跳 depth[y] - depth[x]。

当 x 和 y 在同一深度之后,如果 x = y,那么 x 就是 lca,否则 把 x 和 y 一起往上跳。

由于不知道 lca 的具体位置,因此从大到小枚举 i,尝试是否可以向上跳,直到 pa[x][i] == pa[y][i],循环结束之后,有 lca = pa[x][0]。

练习题目

2836. 在传球游戏中最大化函数值

https://leetcode.cn/problems/maximize-value-of-function-in-a-ball-passing-game/

2846. 边权重均等查询

https://leetcode.cn/problems/minimum-edge-weight-equilibrium-queries-in-a-tree/description/

扩展题目

把练习题目做明白就完了,咱先不扩展。

相关推荐
王老师青少年编程3 小时前
gesp(C++五级)(14)洛谷:B4071:[GESP202412 五级] 武器强化
开发语言·c++·算法·gesp·csp·信奥赛
DogDaoDao3 小时前
leetcode 面试经典 150 题:有效的括号
c++·算法·leetcode·面试··stack·有效的括号
Coovally AI模型快速验证4 小时前
MMYOLO:打破单一模式限制,多模态目标检测的革命性突破!
人工智能·算法·yolo·目标检测·机器学习·计算机视觉·目标跟踪
可为测控4 小时前
图像处理基础(4):高斯滤波器详解
人工智能·算法·计算机视觉
Milk夜雨5 小时前
头歌实训作业 算法设计与分析-贪心算法(第3关:活动安排问题)
算法·贪心算法
BoBoo文睡不醒5 小时前
动态规划(DP)(细致讲解+例题分析)
算法·动态规划
apz_end6 小时前
埃氏算法C++实现: 快速输出质数( 素数 )
开发语言·c++·算法·埃氏算法
仟濹6 小时前
【贪心算法】洛谷P1106 - 删数问题
c语言·c++·算法·贪心算法
CM莫问7 小时前
python实战(十五)——中文手写体数字图像CNN分类
人工智能·python·深度学习·算法·cnn·图像分类·手写体识别
sz66cm7 小时前
LeetCode刷题 -- 45.跳跃游戏 II
算法·leetcode