理解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]。

完成對子樹的搜索和詢問后,需將子樹根結點並入父結點所在集合,這也是整個算法的精妙所在。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM