6576: 点的距离 倍增LCA

发布时间 2023-09-15 15:50:35作者: CRt0729

描述

 

给定一棵 n 个点的树,Q 个询问,每次询问点 x 到点 y 两点之间的距离。

 

输入

 

第一行一个正整数 n,表示这棵树有 n 个节点;

接下来 n−1 行,每行两个整数 x,y表示 x,y 之间有一条连边;

然后一个整数 Q,表示有 Q 个询问;

接下来 Q 行每行两个整数 x,y 表示询问 x 到 y 的距离。

对于全部数据,1≤n≤105,1≤x,y≤n

 

输出

 

输出 Q 行,每行表示每个询问的答案。

 

样例输入

 

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

样例输出

3
4

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10,inf = 0x3f3f3f3f;
struct node{
    int to,next,w; 
    //to:第cnt条边的终点 
    //next:第cnt条边的起点的上一条边是第几条边
    //w:第cnt条边的权值 
};
node edge[2 * N];
int head[2 * N],cnt = 1; //链式前向星数组大小2 * N,边数从1开始 
int n,m,x,y;
int dep[N],f[N][21]; //dep[i]第i个点当前的深度,f[i][k]表示第i个点向上2^k层的父节点是谁 
void add(int u,int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}
void init(int u,int fa)
{
    dep[u] = dep[fa] + 1;
    for(int i = 1; (1<<i) <= dep[u]; i++)
        f[u][i] = f[f[u][i - 1]][i - 1];
    for(int i = head[u]; i; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == fa)continue;
        f[v][0] = u;
        init(v,u);
    }
}
int lca(int x,int y)
{
    if(dep[x] < dep[y])swap(x,y);
    for(int i = 20; i >= 0; i--)
    {
        if(dep[f[x][i]] >= dep[y]) x = f[x][i]; //深度还没有统一
        if(x == y)return x; 
    }
    for(int i = 20; i >= 0; i--)
    {
        if(f[x][i] != f[y][i])
        {
            x = f[x][i],y = f[y][i];
        }
    }
    return f[x][0]; //x往前再走一步就是x,y的最近公共祖先 
}
int dist(int x,int y)
{
    return dep[x] + dep[y] - 2 * dep[lca(x,y)];
}
int main()
{
    cin >> n;
    for(int i = 1; i < n; i++)
    {
        scanf("%d %d",&x,&y);
        add(x,y);
        add(y,x);
    }
    init(1,0);
    cin >> m;
    while(m--)
    {
        scanf("%d %d",&x,&y);
        printf("%d\n",dist(x,y));
    }
     return 0;
}