メモ帳

楽しいアウトプットの場所

木構造の最短経路問題 ABC-70D Transit Tree Path

問題文

N頂点の木が与えられます。
木とはグラフの一種であり、頂点の数をNとすると、辺の数がN-1本である閉路の無い連結グラフです。
i(1\leq i \leq N-1)番目の辺は頂点a_iと頂点b_iを距離c_iで結びます。
また、Q個の質問クエリと整数Kが与えらえます。
j(1\leq j \leq Q)番目の質問クエリでは、頂点x_jから頂点Kを経由しつつ、頂点y_jまで移動する場合の最短経路の距離を求めて下さい。
atcoder.jp

考えたこと

  1. 頂点xから頂点yへの頂点Kを経由する場合の最短経路は、頂点Kからxへの最短経路と頂点Kからyへの最短経路の和で求まる。
  2. 最初ダイクストラ法で実装しようとしたが、よく考えたら、閉路が無い木構造であり、ある頂点からある頂点までの経路が一つしかないため、深さ優先探索(dfs)で探索すれば十分であることが分かった。
  3. 辺の数がn-1なので、間違えてforループをn回すとバグらせるので注意が必要。
const int limit = 100010;
using edge = struct{ll to; ll cost;};
vector<edge> tree[limit];
ll depth[limit];


void dfs(ll v, ll p, ll d){
    depth[v] = d;
    for(auto &e : tree[v]){
        if(e.to == p) continue;
        dfs(e.to, v, d+e.cost);
    }
}

int main() {
    ll n; cin >> n;
    for(ll i=0; i<n-1; i++){
        ll a, b, c; cin >> a >> b >> c;
        tree[a].push_back({b, c});
        tree[b].push_back({a, c});
    }

    ll Q, K; cin >> Q >> K;
    dfs(K, -1, 0);

    for(ll i=0; i<Q; i++){
        ll x, y; cin >> x >> y;
        cout << depth[x]+depth[y] << '\n';
    }


    return 0;
}