小A的最短路(LCA、倍增算法学习)

链接:https://ac.nowcoder.com/acm/contest/549/F
来源:牛客网
 

小A的最短路

时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小A这次来到一个景区去旅游,景区里面有N个景点,景点之间有N-1条路径。小A从当前的一个景点移动到下一个景点需要消耗一点的体力值。但是景区里面有两个景点比较特殊,它们之间是可以直接坐观光缆车通过,不需要消耗体力值。而小A不想走太多的路,所以他希望你能够告诉它,从当前的位置出发到他想要去的那个地方,他最少要消耗的体力值是多少。

输入描述:

第一行一个整数N代表景区的个数。
接下来N-1行每行两个整数u,v代表从位置u到v之间有一条路径可以互相到达。
接下来的一行两个整数U,V表示这两个城市之间可以直接坐缆车到达。
接下来一行一个整数Q,表示有Q次询问。
接下来的Q行每行两个整数x,y,代表小A的位置在x,而他想要去的地方是y。

输出描述:

对于每个询问下x,y输出一个结果,代表x到y消耗的最少体力对于每个询问下x,y输出一个结果,代表x到y消耗的最少体力

示例1

输入

复制

4
1 2
1 3
2 4
3 4
2
1 3
3 4

输出

复制

1
0

备注:

1≤N≤3e5, 1≤Q≤1e6

下面这个视频讲解了联通分量和双连通分量以及LCA和最小树形图,挺不错的,看了一个小时基本就全懂了,好评~

https://www.bilibili.com/video/av27601307?share_medium=android&share_source=qq&bbid=2CA0A464-229E-40EA-9C93-EACE480D55486685infoc&ts=1555413736500

https://www.bilibili.com/video/av27601307?share_medium=android&share_source=qq&bbid=2CA0A464-229E-40EA-9C93-EACE480D55486685infoc&ts=1555413736500

然后再根据题解做题就可以了。

#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int N = 3e5 + 10;
int n,U,V;
int dep[N],dU[N],dV[N];
int fa[N][22];
vector<int> G[N];
int lca(int u,int v) {
    if(dep[u] > dep[v]) swap(u,v);
    for(int k = 20;k >= 0;k--) {
        if(dep[v] - dep[u] >= (1 << k)) {
            v = fa[v][k];
        }
    }
    if(u == v) return u;
    for(int k = 20;k >= 0;k--) {
        if(fa[u][k] != fa[v][k]) {
            u = fa[u][k];
            v = fa[v][k];
        }
    }
    return fa[u][0];
}
int query(int u,int v) {
    return dep[u] + dep[v] - 2 * dep[lca(u,v)];  
}
void dfs(int u,int f,int d) {
    fa[u][0] = f;
    dep[u] = d;
    for(int i=0;i<G[u].size();i++)
    {
    	int v=G[u][i];if(v != f) dfs(v,u,d + 1);
	}
    
}
void init() {
    for(int k = 1;k <= 20;k++) {
        for(int i = 1;i <= n;i++) {
            fa[i][k] = fa[fa[i][k - 1]][k - 1];
        }
    }
}
bool vis[N];
void bfs(int u,int *d) {
    memset(vis,0,sizeof(vis));
    queue<P> Q;
    Q.push(P {u,0});
    vis[u] = 1;
    while(!Q.empty()) {
        P p = Q.front(); Q.pop();
        for(int i=0;i<G[p.first].size();i++)
     	{
        	int v=G[p.first][i];
            if(!vis[v]) {
                vis[v] = 1;
                d[v] = p.second + 1;
                Q.push(P {v,d[v]});
            }
        }
    }
}
int main() {
    ios::sync_with_stdio(false); 
	cin.tie(0); cout.tie(0);
    cin >> n;
    for(int i = 1;i < n;i++) {
        int u,v;
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,0,0);
    init();
    int Q;
    cin >> U >> V >> Q;
    bfs(U,dU);
    bfs(V,dV);
    while(Q--) {
        int u,v;
        cin >> u >> v;
        cout << min(query(u,v),min(dU[u] + dV[v],dU[v] + dV[u])) << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/89341944