P3379 【模板】最近公共祖先(LCA)
--------------------------------
--------------------------------
这道题我们要用到一种很神奇的东西,倍增。
首先,我们考虑一下最简单的做法,记录深度。然后先让询问的x,y中深度大的点往上爬,直到两个点深度一样结束。
然后两个点同时开始爬,当两个点相等时,就一定是公共祖先了
--------------------------------
但是一个一个爬太慢了,怎么办呢?
我们就会用到一个东西,倍增。
每次增加2^k幂
--------------------------------
没听懂?何不看看代码。
其中depth表示深度。
f[i][j]表示从i向上爬2^j后的祖先节点。
-----------------------------------
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int maxn= 2*500001; 5 struct kkk{ 6 int t; 7 int next; 8 }b[maxn]; 9 int depth[maxn],fa[maxn][22],logg[maxn],head[maxn]; 10 int cnt; 11 int add(int x,int y){ 12 cnt++; 13 b[cnt].t=y; 14 b[cnt].next=head[x]; 15 head[x]=cnt; 16 } 17 void dfs(int f,int fath){//预处理 18 depth[f]=depth[fath]+1; 19 fa[f][0]=fath; 20 for(int i=1;(1<<i)<=depth[f];i++){//因为深度有限。所以往上爬也有限 21 fa[f][i]=fa[fa[f][i-1]][i-1]; 22 } 23 for(int i=head[f];i;i=b[i].next){ 24 if(b[i].t!=fath) 25 dfs(b[i].t,f);//遍历儿子们 26 } 27 } 28 int lca(int x,int y){ 29 if(depth[x]<depth[y]) 30 swap(x,y); 31 while(depth[x]>depth[y])//首先让深度相同 32 x=fa[x][logg[depth[x]-depth[y]]-1]; 33 if(x==y) 34 return x;//特别的 35 for(int k=logg[depth[x]]-1;k>=0;k--)//倍增算法 36 if(fa[x][k]!=fa[y][k]) 37 x=fa[x][k],y=fa[y][k]; 38 return fa[x][0]; 39 } 40 int n,m,s; 41 int main(){ 42 scanf("%d%d%d",&n,&m,&s); 43 for(int i=1;i<=n-1;++i){ 44 int x,y; 45 scanf("%d%d",&x,&y); 46 add(x,y); 47 add(y,x); 48 } 49 dfs(s,0); 50 for(int i=1;i<=n;++i) 51 logg[i]=logg[i-1]+(1<<logg[i-1]==i); 52 for(int i=1;i<=m;++i) 53 { 54 int x,y; 55 scanf("%d%d",&x,&y); 56 printf("%d\n",lca(x,y)); 57 } 58 return 0; 59 }