zoukankan      html  css  js  c++  java
  • 理解LCA离线算法

    该算法也是tarjan发现的,故也叫tarjan算法。
    这个算法的主体还是dfs,先看算法框架:

    void make_set(int i)
    {
     p[i]=i;
    }

    int find_set(int i)
    {
     if(i!=p[i]) p[i]=find_set(p[i]);
     return p[i];
    }

    union_set(int i,int j)
    {
     i=find_set(i),j=find_set(j);
     p[j]=i;
    }
    //tarjan算法主体
    void dfs(int u)
    {
     int i,v;
     make_set(u);
     for(i=0;i<g[u].size();i++)
     {
      v=g[u][i];
      if(p[v]==-1)
      {
       dfs(v);
       union_set(u,v);
      }
     }
     for(v=0;v<n;v++)
     {
      if(p[v]!=-1)
      {
       lca[u][v]=lca[v][u]=find_set(v);
      }
     }
    }

    前3个是并查集的函数,这里就不分析了,主要分析dfs:

    当dfs到某个结点时,该结点自成一个集合,即p[u]=u,这个数组同时还能作为dfs的标记,当完成某棵子树的搜索后,假设该子树的根为u,任意其他已经标记过的结点v,

    若v是u的祖先,则可以肯定以v为根的子树的搜索尚未完成,所以v仍然自成一个集合,此时lca(u,v)=p[v]=v;

    若v是u的子孙结点,则可以肯定以v为根的子树的搜索已经完成,v已经被并入u所在的集合,所以lca(u,v)=p[v]=u;

    若v是u的兄弟结点或其兄弟结点的子孙结点,设u的父亲结点为w,则可以肯定以v为根的子树的搜索已经完成,但以w为结点的子树的搜索尚未完成,所以v已经并入w所在集合,lca(u,v)=p[v]=p[w]=w;

    终上所述,每次完成以u为根的子树的dfs时,对于其他已经标记过的结点v,lca(u,v)=p[v]。

    完成对子树的搜索和询问后,需将子树根结点并入父结点所在集合,这也是整个算法的精妙所在。

  • 相关阅读:
    redis 安装配置
    ORM 效率补充
    function*
    路由器
    nodejs开发辅助工具nodemon
    npm淘宝镜像配置
    Node中的模块系统
    artTemplate不仅可以在浏览器中使用,还可以在node中使用
    代码风格JavaScript standard style与Airbnb style
    osChina.net工具
  • 原文地址:https://www.cnblogs.com/algorithms/p/2580290.html
Copyright © 2011-2022 走看看