小A的最短路 | LCA

小A的最短路

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

首先题目给出是一棵树

我们可以知道树上两点路径唯一

其次又有一条额外免费的边

所以我们可以这么考虑,x,y之间的路径要么是 在原树上由x到y,要么经过额外免费的边

对于每个询问,取三种情况最小值即可

ll n,m,p;
struct node{
    int e,next;
}edge[maxn];
int head[maxn];
int deep[maxn];
int f[maxn][21];
ll cnt = 0;
void addedge(int u,int v){
    edge[cnt] = node{v,head[u]};
    head[u] = cnt ++;
}
void dfs(int u,int fa){
    deep[u]=deep[fa]+1;
    f[u][0]=fa;
    for(int i=1;(1<<i)<=deep[u];i++)
        f[u][i]=f[f[u][i-1]][i-1];
    for(int i=head[u];~i;i=edge[i].next){
        int e=edge[i].e;
        if(e!=fa) dfs(e,u);
    }
}
int LCA(int u,int v)
{
    if(deep[u]<deep[v]) swap(u,v);
    for(int i=19;i>=0;i--)   if(deep[f[u][i]]>=deep[v]) u=f[u][i];//比他深往上跳
    if(u==v) return u;
    for(int i=19;i>=0;i--){
        if(f[u][i]!=f[v][i]){//因为从同一深度开始向上跳 一样有可能是更远的祖先
            u=f[u][i];
            v=f[v][i];
        }
    }
    return f[u][0];//随便返回一个上一级即可
}
ll dis(int u,int v){
    return deep[u] + deep[v] - 2*deep[LCA(u,v)];
}
int main()
{
    memset(head,-1,sizeof(head));
    read(n);
    for(int i=1;i<=n-1;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);addedge(y,x);
    }
    for(int i=1;i<=n;i++)
        if(!deep[i]) dfs(i,i);
    ll sx,sy;read(sx);read(sy);
    read(m);
    for(int i=1;i<=m;i++){
        int x,y;scanf("%d%d",&x,&y);
        printf("%lld\n",min(dis(x,y),min(dis(x,sx)+dis(sy,y),dis(x,sy)+dis(sx,y))));
    }
    return 0;
}
全部评论

相关推荐

废铁汽车人:秋招真是牛鬼蛇神齐聚一堂
点赞 评论 收藏
分享
11-01 20:03
已编辑
门头沟学院 算法工程师
Amazarashi66:这种也是幸存者偏差了,拿不到这个价的才是大多数
点赞 评论 收藏
分享
头像
11-26 15:46
已编辑
中南大学 后端
字节国际 电商后端 24k-35k
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务