【lca】点的距离

4 篇文章 0 订阅

题目描述

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

输入

第一行一个n,表示有n个节。

接下来有n-1行,每行2个整数x,y表示x,y之间有一条连边。

然后一个整数Q,表示有Q次询问,接下来Q行每行2个整数x,y表示询问x到y的距离。

输出

输出Q行,每行表示每个询问的结果

样例输入

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

样例输出

3
4

思路:倍增法求lca板子题,dfs+打表+查询就ok,只需在输出结果时稍微加减即可(注释有写

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 4e5+10;
int n,q,num_edge;
int f[maxn],depth[maxn];
//f记录父节点,depth记录深度
int st[30][maxn];
//第一维i表示跳2^i层,第二维j表示开始跳的起点
//数组内存的数据表示跳到的终点
int first[maxn],Next[2*maxn],v[2*maxn];
//v记录边的终点,Next记录上一条边的标号
//first记录最后一条边的标号
void road(int x,int y) //记录从x到y的一条边
{
    v[++num_edge]=y;//记录终点为y
    Next[num_edge]=first[x];//新边指向之前的最后一条变
    first[x]=num_edge;//更新最后一条边
}
void dfs(int son,int father)
{
    f[son]=father;//记录son点的父节点
    //将从son出发的每条边都进行进一步的深搜
    for(int i = first[son]; i!=-1; i=Next[i])
    {
        int to = v[i];//取出遍历到的边的终点
        if(to==father)continue;//防止死循环
        depth[to]=depth[son]+1;
        dfs(to,son);
    }
}
int get_lca(int x,int y)
{
    if(depth[x]<depth[y])swap(x,y);//保证x比y深
    //使x到达与y的共同深度
    for(int i = 20; i >= 0; i--)
        if(depth[st[i][x]]>=depth[y])
            x=st[i][x];
    //如果y就是x的父节点,则两者的第一个共同根节点就是y
    if(x==y)return x;
    //一步步往上跳以寻找xy的最后一个依旧不相同的根节点
    for(int i = 20; i >= 0; i--)
        if(st[i][x]!=st[i][y])
            x=st[i][x],y=st[i][y];
    //最后一个不相同根节点的父节点即所求答案
    return f[x];
}
int main()
{
    int x,y;
    cin>>n;
    memset(first,-1,sizeof(first));
    num_edge=0;
    //存下每一条边
    for(int i = 1; i < n; i++)
    {
        scanf("%d %d",&x,&y);
        road(x,y),road(y,x);
    }
    //预处理depth
    depth[1]=1;//根节点深度为1
    dfs(1,0);//处理剩余的depth
    //准备st表
    //如果跳2^0层即跳一层,则会跳到自己的父节点
    for(int i = 1; i <= n; i++)
        st[0][i]=f[i];
    //如果从j跳2^i层能到达st[i][j]
    //因为2^(i-1)+2^(i-1)=2^i
    //那么从j跳2^(i-1)层所到达的点再跳2^(i-1)层也能到st[i][j]
    for(int i = 1; i <= 20; i++)
        for(int j = 1; j <= n; j++)
            st[i][j]=st[i-1][st[i-1][j]];
    //q次查询
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d %d",&x,&y);
        //找到xy的第一个公共父节点
        int father = get_lca(x,y);
        //xy与父节点的深度之差即为距离
        printf("%d\n",depth[x]+depth[y]-2*depth[father]);
    }



    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值