mayoko’s diary

プロコンとかいろいろ。

Codeforces Round #303 (Div. 2) E. Paths and Trees

解法

ダイクストラで最短距離求めた後root以外の各頂点uについてd[u]-e.cost == d[e.to]となるやつのうちe.costが最小のやつを選ぶ。

以下ソースコード

struct edge {
    int to;
    ll cost;
    int id;
    edge(int t, ll c, int i) : to(t), cost(c), id(i) {}
    edge() {}
};

const int MAXN = 300030;
const ll INF = 1ll<<55;
vector<edge> G[MAXN];
int parent[MAXN];
ll d[MAXN];

void dijkstra(int s, int n) {
    priority_queue<pair<ll, int> > que;
    for (int i = 0; i < n; i++) {
        d[i] = INF;
    }
    d[s] = 0;
    que.push(make_pair(0ll, s));
    while (!que.empty()) {
        auto now = que.top(); que.pop();
        ll dist = -now.first;
        int v = now.second;
        if (d[v] < dist) continue;
        for (auto e : G[v]) {
            if (d[e.to] > d[v]+e.cost) {
                d[e.to] = d[v]+e.cost;
                que.push(make_pair(-d[e.to], e.to));
            }
        }
    }
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int u, v;
        ll cost;
        cin >> u >> v >> cost;
        u--; v--;
        G[u].push_back(edge(v, cost, i+1));
        G[v].push_back(edge(u, cost, i+1));
    }
    int s;
    cin >> s;
    s--;
    if (n == 1) {
        cout << 0 << endl;
        return 0;
    }
    dijkstra(s, n);
    vector<int> ans;
    ll all = 0;
    for (int i = 0; i < n; i++) {
        if (i == s) continue;
        ll minCost = INF;
        int id = 0;
        for (auto e : G[i]) {
            if (d[i]-e.cost == d[e.to]) {
                if (minCost > e.cost) {
                    minCost = e.cost;
                    id = e.id;
                }
            }
        }
        all += minCost;
        ans.push_back(id);
    }
    cout << all << endl;
    sort(ans.begin(), ans.end());
    for (int el : ans) {
        cout << el << " ";
    }
    cout << endl;
    return 0;
}