倍增LCA模板
阿新 • • 發佈:2018-11-21
注意!本篇題解不適合初學LCA的同學學習,因為我講的很爛很不清楚。
倍增,顧名思義,就是成倍增加的意思。
我們知道,任何一個數字都可以表示成二進位制。那麼對於一條長度為n的鏈,我們總是可以跳大概logn次到達最後。
對於鏈上任意一點,我們都可以在大概logn的複雜度下詢問到,其實倍增的思路就是二分,和快速冪一模一樣。
那麼怎麼用倍增求LCA呢?
首先在樹上求每個節點的深度,並且更新每個節點的祖先節點。假如有A和B兩個結點,我們就假設深度大的為A,我們可以在logn的複雜度下跳到B的深度,然後A和B同時在logn的複雜度下跳到LCA。
所以倍增求LCA的複雜度是logn的啦。
下面上程式碼吧:(這是一份常數極大的模板,慎用。)
#include <bits/stdc++.h> using namespace std; const int maxn = 5e5+7; const int maxl = 21; int fa[maxn][maxl]; int depth[maxn]; int lg[maxn]; vector<int> G[maxn]; void dfs(int now,int last) { depth[now] = depth[last]+1; fa[now][0] = last; for(int i=1;(1<<i)<=depth[now];i++) { fa[now][i] = fa[fa[now][i-1]][i-1]; } for(int i=0;i<G[now].size();i++) { if(G[now][i]!=last) dfs(G[now][i],now); } } int lca(int x,int y) { if(depth[x]>depth[y]) swap(x,y); while(depth[x]!=depth[y]) y = fa[y][lg[depth[y]-depth[x]]-1]; if(x==y) return x; for(int k=lg[depth[y]];k>=0;k--) { if(fa[x][k]!=fa[y][k]) { x = fa[x][k]; y = fa[y][k]; } } return fa[x][0]; } int main() { int n,m,s; scanf("%d%d%d",&n,&m,&s); int x,y; for(int i=0;i<n-1;i++) { scanf("%d%d",&x,&y); G[x].push_back(y); G[y].push_back(x); } for(int i=1;i<=n;i++) { lg[i] = lg[i-1]+(1<<lg[i-1]==i); } dfs(s,0); for(int i=0;i<m;i++) { scanf("%d%d",&x,&y); printf("%d\n",lca(x,y)); } return 0; }