Submission #1293585

#TimeUsernameProblemLanguageResultExecution timeMemory
1293585thaibeo417Robot (JOI21_ho_t4)C++20
100 / 100
211 ms65328 KiB
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
const ll INF = (ll)4e18;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, M;
    if (!(cin >> N >> M)) return 0;

    // V[u] : các cạnh kề với u, lưu (màu, (chi phí P, đỉnh kề))
    vector<vector<pair<int, pair<ll,int>>>> V(N + 1);

    for (int i = 0; i < M; ++i) {
        int a, b, c;
        ll p;
        cin >> a >> b >> c >> p;
        V[a].push_back({c, {p, b}});
        V[b].push_back({c, {p, a}});
    }

    // Số đỉnh tối đa trong đồ thị mở rộng:
    // ban đầu có N đỉnh gốc, thêm tối đa 2*M đỉnh màu-đỉnh
    int maxNodes = N + 2 * M + 5;
    vector<vector<pair<ll,int>>> G(maxNodes); // G[u] : (cost, v)

    int sz = N; // đếm số đỉnh hiện tại trong đồ thị mở rộng

    // Xây đồ thị mở rộng
    for (int u = 1; u <= N; ++u) {
        if (V[u].empty()) continue;

        // Gom các cạnh theo màu
        auto &vec = V[u];
        sort(vec.begin(), vec.end(),
             [](const auto &A, const auto &B) {
                 if (A.first != B.first) return A.first < B.first;
                 // phụ cho ổn định, không bắt buộc
                 return A.second.second < B.second.second;
             });

        int nAdj = (int)vec.size();
        int l = 0;
        while (l < nAdj) {
            int r = l;
            int color = vec[l].first;
            ll sumP = 0;

            // [l, r) là nhóm cùng màu "color" tại đỉnh u
            while (r < nAdj && vec[r].first == color) {
                sumP += vec[r].second.first;
                ++r;
            }

            int cnt = r - l;

            if (cnt == 1) {
                // Chỉ có 1 cạnh màu này ở u:
                // đi qua cạnh này từ u sang v với cost 0
                int v = vec[l].second.second;
                G[u].push_back({0, v});
            } else {
                // Có >= 2 cạnh cùng màu tại u
                // tạo đỉnh trung gian nodeColor = (u, color)
                int nodeColor = ++sz;

                // từ u sang nodeColor (chuẩn bị thực hiện move Y) với cost 0
                G[u].push_back({0, nodeColor});

                // duyệt từng cạnh trong nhóm
                for (int j = l; j < r; ++j) {
                    ll p = vec[j].second.first;
                    int v = vec[j].second.second;

                    // 1) di chuyển kiểu X: tô riêng cạnh này, từ u sang v, cost = p
                    G[u].push_back({p, v});

                    // 2) bước X của cặp (X,Y): từ v sang nodeColor với cost 0
                    G[v].push_back({0, nodeColor});

                    // 3) bước Y: từ nodeColor sang v, cost = tổng P các cạnh cùng màu trừ cạnh này
                    G[nodeColor].push_back({sumP - p, v});
                }
            }

            l = r;
        }
    }

    // Dijkstra trên đồ thị mở rộng
    vector<ll> dist(sz + 1, INF);
    priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;

    dist[1] = 0;
    pq.push({0, 1});

    while (!pq.empty()) {
        auto [d, u] = pq.top();
        pq.pop();
        if (d != dist[u]) continue;

        for (auto [w, v] : G[u]) {
            if (dist[v] > d + w) {
                dist[v] = d + w;
                pq.push({dist[v], v});
            }
        }
    }

    if (dist[N] == INF) cout << -1;
    else cout << dist[N];

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...