P3379 【模板】最近公共祖先(LCA)

--------------------------------

链接:P3379 【模板】最近公共祖先(LCA)

--------------------------------

这道题我们要用到一种很神奇的东西,倍增。

首先,我们考虑一下最简单的做法,记录深度。然后先让询问的x,y中深度大的点往上爬,直到两个点深度一样结束。

然后两个点同时开始爬,当两个点相等时,就一定是公共祖先了

--------------------------------

但是一个一个爬太慢了,怎么办呢?

我们就会用到一个东西,倍增。

每次增加2^k幂

--------------------------------

没听懂?何不看看代码。

其中depth表示深度。

f[i][j]表示从i向上爬2^j后的祖先节点。

-----------------------------------

 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
",lca(x,y));
57         }
58     return 0;
59 }
Ac
原文地址:https://www.cnblogs.com/For-Miku/p/11257972.html