解法

概要

木DP。 各部分木について根を含む連結成分に「たぷを含むよう切るときの最小コスト」「たぴを含むよう切るときの最小コスト」「どちらも含まないように切るときの最小コスト」を求める。 $O(N)$。

メモ

  • 手癖でACすると解説読んだ後「なるほど私の実装はそういう意味だったのかあ」になりがち
  • 部分点は最小カット

実装

#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0; (i) < (int)(n); ++ (i))
using ll = long long;
using namespace std;
template <class T, class U> inline void chmin(T & a, U const & b) { a = min<T>(a, b); }

struct node_t {
    ll cost_p, cost_q, cut;
};

ll solve(int n, int x, int y, vector<vector<pair<int, int> > > const & g, vector<char> const & type) {
    constexpr ll INF = (ll)1e18 + 9;
    function<node_t (int, int)> go = [&](int i, int parent) {
        node_t cur = {};
        cur.cut = INF;
        for (auto edge : g[i]) {
            int j; ll cost; tie(j, cost) = edge;
            if (j == parent) continue;
            node_t prv = go(j, i);
            cur.cost_p += min(prv.cost_p, prv.cost_q + min(cost, prv.cut));
            cur.cost_q += min(prv.cost_q, prv.cost_p + min(cost, prv.cut));
            cur.cut = min(INF, cur.cut + prv.cut);
        }
        if (type[i] == 'P') cur.cost_q = cur.cut = INF;
        if (type[i] == 'Q') cur.cost_p = cur.cut = INF;
        return cur;
    };
    node_t cur = go(0, -1);
    return min(cur.cost_p, cur.cost_q);
}

int main() {
    int n, x, y; cin >> n >> x >> y;
    vector<vector<pair<int, int> > > g(n);
    REP (i, n - 1) {
        int a, b, v; cin >> a >> b >> v;
        -- a; -- b;
        g[a].emplace_back(b, v);
        g[b].emplace_back(a, v);
    }
    vector<char> type(n);
    REP (i, x) {
        int p; cin >> p; -- p;
        type[p] = 'P';
    }
    REP (i, y) {
        int q; cin >> q; -- q;
        type[q] = 'Q';
    }
    cout << solve(n, x, y, g, type) << endl;
    return 0;
}