题目

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

解题思路

利用 LCA 求树上的任意两点距离。

如果不坐缆车,此时消耗体力值为
如果坐缆车,有 2 种情况:
① 从点 x 到达点 U,坐缆车到 V,再从 V 到达 y。此时消耗体力值为
① 从点 x 到达点 V,坐缆车到 U,再从 U 到达 y。此时消耗体力值为

取上面三种消耗体力值的最小值。

C++代码

#include<iostream>
#include<vector>
using namespace std;

vector<vector<int>> edges;
vector<int> father;
vector<int> deep;

void dfs(int s, int fa){
    father[s] = fa;
    for(auto e : edges[s]){
        if(e==fa) continue;
        deep[e] = deep[s] + 1;
        dfs(e, s);
    }
}

int lca(int a, int b){
    if(deep[a] < deep[b])
        swap(a,b);
    while(deep[a] > deep[b])
        a = father[a];
    while(a!=b){
        a = father[a];
        b = father[b];
    }
    return a;
}

int dist(int a, int b){
    int an = lca(a,b);
    int d = deep[a] + deep[b] - 2*deep[an];
    return d;
}

int main(){
    int n, q;
    cin >> n;
    edges.resize(n+1);
    deep.resize(n+1,0);
    father.resize(n+1,0);
    int u, v;
    for(int i=0; i<n-1; ++i){
        cin >> u >> v;
        edges[u].push_back(v);
        edges[v].push_back(u);
    }
    dfs(1,0);
    int U, V;
    cin >> U >> V;
    cin >> q;
    int x, y;
    while(q--){
        cin >> x >> y;
        int d = dist(x,y);
        d = min(d, dist(x,U)+dist(V,y));
        d = min(d, dist(x,V)+dist(U,y));
        cout << d << endl;
    }
    return 0;
}