LCA模板题

难度 普及+/提高


题目描述

给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入输出格式

输入格式

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

输入输出样例

输入样例

5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5

输出样例

4
4
1
4
4

样例说明

该树结构如下:

第一次询问:2、4的最近公共祖先,故为4。

第二次询问:3、2的最近公共祖先,故为4。

第三次询问:3、5的最近公共祖先,故为1。

第四次询问:1、2的最近公共祖先,故为4。

第五次询问:4、5的最近公共祖先,故为4。

故输出依次为4、4、1、4、4。


代码

#include
#define MN 500005
using namespace std;
int m,n,s,tot,dep[MN],up[MN][20];

struct lll
 {
    int to;
    lll *ne;
 }a[2*MN];

lll *head[MN];

void DFS(int u)
{

    for(int i=1;(1<1]][i-1];
     }

    for(lll *e=head[u];e;e=e->ne)
     {
        if(dep[e->to]==-1)
         {
            dep[e->to]=dep[u]+1;
            up[e->to][0]=u;
            DFS(e->to);
         }
     }  

     return;
}

int LCA(int u,int v)
{
    if(dep[v]>dep[u]) swap(u,v);

    for(int i=19;i>=0;i--)
    {
        if(dep[up[u][i]]>=dep[v])
         u=up[u][i];
    }

    if(u==v) return v;

    for(int i=19;i>=0;i--)
    {
        if(up[u][i]!=up[v][i])
        {
         u=up[u][i];
         v=up[v][i];
        } 
    }

    return up[u][0];
}

int main()
{
   scanf("%d%d%d",&n,&m,&s);

   for(int i=1;iint x,y;
      scanf("%d%d",&x,&y);
      a[++tot].ne=head[x];
      head[x]=&a[tot];
      a[tot].to=y;
      a[++tot].ne=head[y];
      head[y]=&a[tot];
      a[tot].to=x;
    }

   memset(dep,-1,sizeof(dep));
   dep[s]=0;
   up[s][0]=0;
   DFS(s);

   for(int j=1;j<=m;j++)
    {
       int u,v;
       scanf("%d%d",&u,&v);
       printf("%d\n",LCA(u,v));
    }
   return 0;
}
感谢RWZ小朋友的代码资瓷

你可能感兴趣的:(算法,NOIP)