zoukankan      html  css  js  c++  java
  • LCA (最近公共祖先)倍增做法 —— O(nlogn)预处理 O(logn)(在线)查询

    pa[a][j] 表示 a 结点的 2^j倍祖先(j = 0时 为直接父亲,j = 1时为父亲的父亲……)

    1.首先预处理出所有结点的深度值dep和父亲结点

     1 void dfs(int u, int f, int d) {
     2     dep[u] = d;
     3     pa[u][0] = f;
     4     for(int i = 0; i < G2[u].size(); i++) {
     5         edge& e = E[G2[u][i]];
     6         int v = e.u == u ? e.v : e.u;
     7         if(v != f) {
     8             dfs(v, u, d+1);
     9         }
    10     }
    11 }

    2.预处理出所有结点的 2^j 倍祖先

    1 void pre() {
    2     for(int j = 1; (1<<j) < n; j++) 
    3         for(int i = 1; i <= n; i++) if(pa[i][j-1] != -1)
    4             pa[i][j] = pa[pa[i][j-1]][j-1];    
    5 }

    3.查询操作,首先将 a,b中深度较大的结点上升到与深度较小的结点同一深度,然后两个结点同步上移,直到上移到最近公共祖先的直接儿子处。

     1 int lca(int a, int b)//最近公共祖先
     2 {
     3     int i, j;
     4     if(dep[a] < dep[b]) swap(a, b);
     5     for(i = 0; (1<<i) <= dep[a]; i++);
     6     i--;
     7     //使a,b两点的深度相同
     8     for(j = i; j >= 0; j--)
     9         if(dep[a] - (1<<j) >= dep[b])
    10             a=pa[a][j];
    11     if(a == b) return a;
    12     //倍增法,每次向上进深度2^j,找到最近公共祖先的子结点
    13     for(j = i; j >= 0; j--) {
    14         if(pa[a][j] != -1 && pa[a][j] != pa[b][j]) {
    15             a = pa[a][j];
    16             b = pa[b][j];
    17         }
    18     }
    19     return pa[a][0];
    20 }
  • 相关阅读:
    串口通信
    无法安装SQL提示文件被挂起
    flash图片幻灯片浏览
    document.all与WEB标准
    在新窗口中打开页面 的asp.net后台代码
    sql 触发器
    无技术含量的正则表达式笔记
    两个FTP服务器之间传送数据
    repeater嵌套
    登录
  • 原文地址:https://www.cnblogs.com/Kiraa/p/6141217.html
Copyright © 2011-2022 走看看