-
最近公共祖先,顾名思义,就是在一颗树中,去找两个子节点的最近的公共祖先.这处理起来并不复杂,我们可以直接一个一个的暴力去 找,但基本上会TLE.所以我们可以用倍增法来处理LCA的问题.
-
倍增法:每次按\(2\)的倍数增大,即:\(1,2,4,8,16,32.....\),有点类似二进制的枚举,而在当前处理的LCA问题中,我们要从大的向小的来找.
-
具体实现:
-
既然我们是倍增法来处理的,那么我们就要求出每个节点的深度以及它们的前\(2^k\)个祖先.然后我们遍历每个点的深度的对数,即\(lg[depth[node]]-1\)(lg表示\(log_{2}{n}+1\)),求出\(fa[node][i]\),表示节点的\(2^i\)级祖先,而在求的时候要注意,我们更新的时候,要去找当前的这个点的上\(2^{i-1}\)级祖先的上\(2^{i-1}\)级祖先,即:\(2^{i-1}+2^{i-1}=2^i\).
-
代码:
void dfs(int node,int fath){ fa[node][0]=fath; depth[node]=depth[fath]+1; for(int i=1;i<=lg[depth[node]]-1;++i){ fa[node][i]=fa[fa[node][i-1]][i-1]; } for(auto w:V[node]){ if(w!=fath) dfs(w,node); } }
-
预处理完之后,我们就可以来找两个点的LCA了,首先我们要保证\(x\)点是深度大的那个,然后再让它们处于同一深度,此时假如两个点相等,那么\(LCA(x,y)=x\),否则,我们就要用倍增法来查找:
-
首先去找最上面的点(\(2^k\)级祖先),如果\(fa[x][k]=fa[y][k]\),就说明当前这个点已经是它们的公共祖先了,为了求最近,我们再去找x和y的\(2^{k-1}\)级祖先,如果\(fa[x][k-1]!=fa[y][k-1]\),那么说明它们的LCA在其\(2^{k-1}\)级祖先之上,我们更新\(x=fa[x][k-1],y=fa[y][k-1]\),然后再向上去找.容易发现,这样一定能在有限的次数之内找到它们的LCA.
-
代码:
int LCA(int x,int y){ if(depth[x]<depth[y]){ swap(x,y); } while(depth[x]>depth[y]){ x=fa[x][lg[depth[x]-depth[y]]-1]; } if(x==y) return x; for(int k=lg[depth[x]]-1;k>=0;--k){ if(fa[x][k]!=fa[y][k]){ x=fa[x][k]; y=fa[y][k]; } } return fa[x][0]; }
-
最近公共祖先(LCA) 倍增法
猜你喜欢
转载自www.cnblogs.com/lr599909928/p/13364950.html
今日推荐
周排行