Nearest Common Ancestors

Nearest Common Ancestors

题目大意:

求树上两个点的LCA(最近公共祖先)

输入格式:

T代表数据组数,n代表节点数目。

n-1行每行两个数a,b分别代表a是b的父节点,ab间有一条无向边。

最后一行为两个数a,b,代表求a,b的LCA。

输出格式:

对于每一组数据输出LCA

思路:裸的LCA了,那么我们就利用最常规的倍增LCA。

首先要找到整个树的根,找根在这道题中比较简单,通过数据输入可知只要不在第二位的节点就是根节点(因为它没有爸爸)

然后我们对于整个树进行预处理,预处理出每一个节点的深度和它向上跳2的i次幂到达的位置,递推公式f[u][i+1]=f[f[u][i]][i](比较显然的)

我们将查询的设为x,y,并且人为规定x的深度大于y,我们首先把x跳到与y深度相同位置,只有跳完后深度大于等于才跳(只要从大到小枚举2的i次幂就行,二进制拆分原理),然后一起往上跳,只有跳完之后到达的点不相同才跳,最后往上走一个即可。

最后附上本题代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #define maxn 10000
  5 using namespace std;
  6 
  7 struct EDGE
  8 {
  9     int nxt,to;
 10 };
 11 EDGE edge[maxn*2+5];
 12 int T,n,root,cnt;
 13 int head[maxn+5],dep[maxn+5];
 14 int f[maxn+5][25];
 15 bool vis[maxn+5];
 16 
 17 void add(int x,int y)
 18 {
 19     edge[++cnt].to=y;
 20     edge[cnt].nxt=head[x];
 21     head[x]=cnt;
 22 }
 23 void pre_fir(int u,int fa)
 24 {
 25     dep[u]=dep[fa]+1;
 26     for(int i=0;i<=22;i++)
 27     {
 28         f[u][i+1]=f[f[u][i]][i];
 29     }
 30     for(int i=head[u];i;i=edge[i].nxt)
 31     {
 32         if(edge[i].to==fa)
 33         {
 34             continue;
 35         }
 36         f[edge[i].to][0]=u;
 37         pre_fir(edge[i].to,u);
 38     }
 39 }
 40 int LCA(int x,int y)
 41 {
 42     if(dep[x]<dep[y])
 43     {
 44         swap(x,y);
 45     }
 46     for(int i=22;i>=0;i--)
 47     {
 48         if(dep[f[x][i]]>=dep[y])
 49         {
 50             x=f[x][i];
 51         }
 52         if(x==y)
 53         {
 54             return x;
 55         }
 56     }
 57     for(int i=22;i>=0;i--)
 58     {
 59         if(f[x][i]!=f[y][i])
 60         {
 61             x=f[x][i];
 62             y=f[y][i];
 63         }
 64     }
 65     return f[x][0];
 66 }
 67 int main()
 68 {
 69     scanf("%d",&T);
 70     while(T--)
 71     {
 72         memset(vis,0,sizeof(vis));
 73         memset(edge,0,sizeof(edge));
 74         memset(f,0,sizeof(f));
 75         memset(dep,0,sizeof(dep));
 76         memset(head,0,sizeof(head));
 77         cnt=0;
 78         scanf("%d",&n);
 79         for(int i=1;i<=n-1;i++)
 80         {
 81             int x,y;
 82             scanf("%d%d",&x,&y);
 83             vis[y]=1;
 84             add(x,y);
 85             add(y,x);
 86         }
 87         for(int i=1;i<=n;i++)
 88         {
 89             if(vis[i]==0)
 90             {
 91                 root=i;
 92                 break;
 93             }
 94         }
 95         pre_fir(root,0);
 96         int a,b;
 97         scanf("%d%d",&a,&b);
 98         printf("%d
",LCA(a,b));
 99     }
100     return 0;
101 }
原文地址:https://www.cnblogs.com/yufenglin/p/10575449.html