Nearest Common Ancestors(poj 1330)

题意:给定一棵树,询问两个节点的最近公共祖先。

输入:第一行T,表示测试组数。

        每组测试数据包含一个n,表示节点数目,下面n-1行是连接的边,最后一行是询问

输出:共T行,代表每组的测试结果

/*
  倍增LCA 
  注意这是树,所以边是单向的,深搜的时候从根节点开始搜 
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#define M 10010
#define S 20
using namespace std;
int head[M],deep[M],fa[M][S+5],in[M],num,n;
struct node
{
    int u,v,pre;
};node e[M*2];
void add(int x,int y)
{
    ++num;
    e[num].u=x;
    e[num].v=y;
    e[num].pre=head[x];
    head[x]=num;
}
void dfs(int now,int from,int c)
{
    fa[now][0]=from;deep[now]=c;
    for(int i=head[now];i;i=e[i].pre)
      if(e[i].v!=from)
        dfs(e[i].v,now,c+1);
}
void get_fa()
{
    for(int j=1;j<=S;j++)
      for(int i=1;i<=n;i++)
        fa[i][j]=fa[fa[i][j-1]][j-1];
}
int get_same(int a,int t)
{
    for(int i=0;i<=S;i++)
      if(t&(1<<i))
        a=fa[a][i];
    return a;
}
int LCA(int a,int b)
{
    if(deep[a]<deep[b])swap(a,b);
    a=get_same(a,deep[a]-deep[b]);
    if(a==b)return a;
    for(int i=S;i>=0;i--)
      if(fa[a][i]!=fa[b][i])
      {
          a=fa[a][i];
          b=fa[b][i];
      }
    return fa[a][0];
}
void init()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        in[y]++;
        add(x,y);
    }
    int p;
    for(int i=1;i<=n;i++)
      if(!in[i])
      {
          p=i;
          break;
      }
    dfs(p,p,0);
    get_fa();
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d\n",LCA(a,b));
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(e,0,sizeof(e));
        memset(head,0,sizeof(head));
        memset(deep,0,sizeof(deep));
        memset(fa,0,sizeof(fa));
        memset(in,0,sizeof(in));
        num=0;
        init();
    }
    return 0;
}
View Code

 

posted @ 2016-07-09 20:28  karles~  阅读(174)  评论(0编辑  收藏  举报