• 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 }
  • 相关阅读:
    黑客入侵美国一家公司夺走1500万美元?Midge建议你一定要知道
    开始使用AngularJS和ASP。NET MVC -第二部分
    MVC Tempdata,查看并保持混乱
    AngularJS ui-router
    仅限OCR图像的PDF文件。
    FxButton类
    WPF图像按钮100%在XAML
    CFlexiButton类
    一个更好的位图按钮类
    COddButton
  • 原文地址:https://www.cnblogs.com/yufenglin/p/10575449.html
Copyright © 2020-2023  润新知