Nearest Common Ancestors

Nearest Common Ancestors

    题目大意:给你k组数据,每组数据输入一个树和一组询问,询问树上LCA。

    注释:n<=10000。

      想法:咳咳,我初学LCA,先来一道裸题压压惊。LCA?(Least Common Ancestors),是指最近公共祖先。最近公共祖先?是指他们的祖先中距离它们最近者。我们在此介绍一种方法:朴素法。记录一个根节点,由根节点起记录深度。对于一组询问x,y,不妨设deep[x]>deep[y]。显然,任意一个i使得deep[i]<deep[y]都一定不是x和y的LCA。所以,我们先将x移动到和y同样的深度。现在,x和y在同意深度,此时,我们想到,将x和y同时向上移动,知道x==y。这时朴素法求LCA,也是最简单的求LCA的方法。

    最后,附上丑陋的代码... ...

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define N 10010
 5 using namespace std;
 6 int fa[N],to[N],head[N],next[N];
 7 bool v[N];
 8 int deep[N];
 9 int tot;
10 void add(int x,int y)//链式前向星加边
11 {
12     to[++tot]=y;
13     next[tot]=head[x];
14     head[x]=tot;
15 }
16 void dfs(int x,int pre,int step)//dfs处理深度和父亲节点
17 {
18     fa[x]=pre;deep[x]=step;
19     for(int i=head[x];i;i=next[i]) dfs(to[i],x,step+1);
20 }
21 int lca(int x,int y)//求lca。
22 {
23     if(deep[x]<deep[y]) swap(x,y);
24     while(deep[x]>deep[y]) x=fa[x];//将x移动到和y平齐
25     while(x!=y) x=fa[x],y=fa[y];//两个点一起向上走
26     return x;
27 }
28 int main()
29 {
30     int n;
31     int cases;
32     int a,b;
33     int root;
34     int x,y;
35     scanf("%d",&cases);
36     while(cases--)
37     {
38         tot=0;
39         memset(v,false,sizeof(v));
40         // memset(deep,0,sizeof(deep));
41         memset(head,0,sizeof(head));//必须清
42         // memset(fa,0,sizeof(fa));
43         scanf("%d",&n);
44         for(int i=1;i<n;i++)
45         {
46             scanf("%d%d",&a,&b);
47             add(a,b);//加边
48             v[b]=1;
49         }
50         for(int i=1;i<=n;i++)//我想直接处理出根节点,因为我加的是单向边
51         {
52             if(!v[i])
53             {
54                 root=i;
55                 break;
56             }
57         }
58         dfs(root,root,0);
59         scanf("%d%d",&x,&y);
60         printf("%d\n",lca(x,y));
61     }
62     return 0;
63 }

    小结:LCA是一个有意思的点,它包含了一些奇特的性质,在此先不做介绍。

      错误:1.清数组是只需要清tot和head[]数组。

         2.如果加的是单向边,必须预处理根节点。

    

转载于:https://www.cnblogs.com/ShuraK/p/8295536.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值