zoukankan      html  css  js  c++  java
  • LCA + 二分(倍增)

    两个最近的点u和v的最近的公共的祖先称为最近公共祖先(LCA)。普通的LCA算法,每算一次LCA的时间复杂度为线性o(n);

    这里讲LCA + 二分的方法。首先对于任意的节点v,利用其父节点的信息,可以通过par2[v]=par[par[v]]得到向上走两步的节点。依此信息可以通过par4[v]=par2[par2[v]]得到向上走4步的节点。所以,根据此方法可以得到向上走2^k所得到的节点par[k][v]。每次搜索的复杂度为o(log n),预处理par[k][v]的复杂度为o(nlog n)。(我觉得挑战程序设计LCA部分写的挺明白的)

    模版代码如下:

     1 //LCA + 二分
     2 
     3 vector <int> G[MAX_V]; //邻接表
     4 int root; //根的编号
     5 
     6 int par[MAX_LOG_V][MAX_V]; // 向上走2^k所到的父节点编号(根节点的父节点为-1)
     7 int dep[MAX_V]; //节点的深度
     8 
     9 void dfs(int v , int p , int d) { //3个参数分别表示 当前节点 父节点 深度
    10     par[v][0] = p;
    11     dep[v] = d;
    12     for(int i = 0 ; i < G[v].size() ; i++) {
    13         dfs(G[v][i] , v , d + 1);
    14     }
    15 }
    16 //预处理
    17 void init(int n) {
    18     dfs(root , -1 , 0); //预处理出par[0]和dep
    19     for(int k = 0 ; k + 1 < MAX_LOG_V ; k++) {
    20         for(int v = 1 ; v <= n ; v++) {
    21             if(par[k][v] < 0) 
    22                 par[k + 1][v] = -1; //v向上的2 ^ (k + 1)的节点超过根节点
    23             else
    24                 par[k + 1][v] = par[k][par[k][v]]; //v向上的2^k的节点 又向上的2^k个节点,所以是向上2^(k + 1)个节点
    25         }
    26     }
    27 }
    28 //计算u和v的LCA
    29 int lca(int u , int v) {
    30     if(dep[u] < dep[v]) //让u和v向上走到同一深度
    31         swap(u , v);
    32     for(int k = 0 ; k < MAX_LOG_V ; k++) {
    33         if((dep[v] - dep[u]) >> k & 1) { //把深度差化为2进制(快速幂原理) 依次从低位相减
    34             v = par[k][v];
    35         }
    36     }
    37     if(u == v) //要是节点相同则输出LCA
    38         return u;
    39     for(int k = MAX_LOG_V - 1 ; k >= 0 ; k--) { //二分搜索计算LCA
    40         if(par[k][u] != par[k][v]) {  //若他们的2^k节点不相同 则u和v向上移动,一直移动直到他们的上一个节点相同
    41             u = par[k][u];
    42             v = par[k][v];
    43         }
    44     }
    45     return par[0][u];
    46 }
  • 相关阅读:
    Spark在MaxCompute的运行方式
    新功能初探 | MySQL 8.0 Multi-Valued Indexes功能简述
    吐血整理 | 1000行MySQL学习笔记,不怕你不会,就怕你不学!
    阿里巴巴架构师:十问业务中台和我的答案
    C# int?
    页面后退清空缓存
    oracle 中 创建序列sequence
    sql 与 oracle 几个简单语法差别
    oracle 中用法dual
    将DataTable进行分页并生成新的DataTable
  • 原文地址:https://www.cnblogs.com/Recoder/p/5221929.html
Copyright © 2011-2022 走看看