小A的最短路

小A的最短路

https://ac.nowcoder.com/acm/problem/23482

题意:
有一颗n个节点的树,经过一条边消耗一点体力。有两个特殊点之间有一个观光缆车,他们之间不需要消耗体力。有Q个询问,每个询问求从x点到y点消耗体力值最少为多少?

思路:
求任意两点树上的距离应该用LCA.
由于多了个电缆,所以我们从x到y是有3种方案:
①从x直接到y,不坐电缆。
②从x到u,再从u坐电缆到v,最后从v到y。
③从x到v,再从v坐电缆到u,最后从u到y。
我们取这三种方案的最少值就可以了

注意:
lca写的丑的会被卡时间,由于u,v固定,所以可以用dfs先求出树上每一个节点到u,v的距离进行优化。

代码:

#include <bits/stdc++.h>

typedef long long ll;

using namespace std;

const ll inf=998244353;

inline int read()
{
    int x=0, y=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
        {
            y=-y;
        }
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*y;
}

vector<int> g[300005];
int dep[300005], parent[20][300005];
int n;

void dfs(int v,int f,int d)
{
    dep[v]=d;
    parent[0][v]=f;
    for(int k=0;(1<<(k+1))<=dep[v];k++)
    {
         if(parent[k][v]<0)
         {
             parent[k+1][v]=-1;
             break;
         }
         else
         {
             parent[k+1][v]=parent[k][parent[k][v]];
         }
    }
    for(int i=0;i<g[v].size();i++)
    {
        if(g[v][i]!=f)
        {
            dfs(g[v][i],v,d+1);
        }
    }
}

int d1[300005], d2[300005];

void dfs1(int v,int f,int d)
{
    d1[v]=d;
    for(int i=0;i<g[v].size();i++)
    {
        if(g[v][i]!=f)
        {
            dfs1(g[v][i],v,d+1);
        }
    }
}

void dfs2(int v,int f,int d)
{
    d2[v]=d;
    for(int i=0;i<g[v].size();i++)
    {
        if(g[v][i]!=f)
        {
            dfs2(g[v][i],v,d+1);
        }
    }
}

void inti()
{
    memset(parent,-1,sizeof(parent));
    dfs(1,-1,0);
}

int lca(int u,int v)
{
    if(dep[u]<dep[v])
    {
        swap(u,v);
    }
    int s=(int)log2(n);
    for(int k=s;k>=0;k--)
    {
        if((dep[u]-dep[v])>=(1<<k))
        {
            u=parent[k][u];
        }
    }
    if(u==v)
    {
        return u;
    }
    for(int k=s;k>=0;k--)
    {
        if(parent[k][v]!=parent[k][u])
        {
            u=parent[k][u];
            v=parent[k][v];
        }
    }
    return parent[0][u];
}

int dis(int x, int y)
{
    return dep[x]+dep[y]-2*dep[lca(x,y)];
}

int main()
{
    n=read();
    for(int i=1;i<n;i++)
    {
        int u=read(), v=read();
        g[u].push_back(v);
        g[v].push_back(u);
    }
    inti();
    int u, v;
    u=read();
    v=read();
    dfs1(u,-1,0);
    dfs2(v,-1,0);
    int q=read();
    while(q--)
    {
        int x=read(), y=read();
        printf("%d\n",min(dis(x,y),min(d1[x]+d2[y],d1[y]+d2[x])));
    }
    return 0;
}
全部评论

相关推荐

Yushuu:你的确很厉害,但是有一个小问题:谁问你了?我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了😆
点赞 评论 收藏
分享
头像
10-15 22:27
已编辑
门头沟学院 C++
罗格镇的小镇做题家:我投了hr打电话来说学历太低了不符合要求,建议投荣耀,结果荣耀也投了一定水花没有,非本211硕
投递华为等公司10个岗位
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务