【最近公共祖先】洛谷_3379 最近公共祖先(LCA)

题意

给出一个树,有m次询问,求出这两个节点的最近公共祖先。

思路

用倍增的方法。先让两个节点的深度相同,然后每次一起跳,就能得到答案了。

代码

#include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
    int to,next;
}e[500001<<1];
int n,m,s,tot,d[500001],head[500001],t,f[500001][20];
inline void add(int u,int v) {e[++tot].to=v;e[tot].next=head[u];head[u]=tot;}
inline void bfs(int s)//求深度 初始化f
{
    int x,y;
    queue<int> q;
    d[s]=1;
    q.push(s);
    while (q.size())
    {
        x=q.front();q.pop();
        for (int i=head[x];i;i=e[i].next)
        {
            y=e[i].to;
            if (d[y]) continue;
            d[y]=d[x]+1;
            f[y][0]=x;
            for (int j=1;j<=t;j++) f[y][j]=f[f[y][j-1]][j-1];
            q.push(y);
        }
    }
}
inline int LCA(int x,int y)
{
    if (d[x]>d[y]) swap(x,y);
    for (int i=t;i>=0;i--)
        if (d[f[y][i]]>=d[x]) y=f[y][i];//调整深度
    if (x==y) return x;//如果已经相等了就说明其中一个就是答案
    for (int i=t;i>=0;i--) //跳
        if (f[x][i]!=f[y][i]) 
        {
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];//因为不相同才跳,所以再跳一次就是答案了
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    int x,y;
    t=log(n)/log(2);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    bfs(s);
    while (m--)
    {
        scanf("%d%d",&x,&y);
        printf("%d\n",LCA(x,y));
    }
}

猜你喜欢

转载自blog.csdn.net/SSL_hzb/article/details/81662674