【算法】树上倍增 & 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/

扩展题目

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

相关推荐
劲夫学编程23 分钟前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪25 分钟前
孤岛的总面积(Dfs C#
算法·深度优先
浮生如梦_2 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师4 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
wheeldown5 小时前
【数据结构】选择排序
数据结构·算法·排序算法
观音山保我别报错6 小时前
C语言扫雷小游戏
c语言·开发语言·算法
TangKenny8 小时前
计算网络信号
java·算法·华为
景鹤8 小时前
【算法】递归+深搜:814.二叉树剪枝
算法