Submission #1340115

#TimeUsernameProblemLanguageResultExecution timeMemory
1340115miraclemagicianCommuter Pass (JOI18_commuter_pass)C++20
100 / 100
188 ms26140 KiB
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;
using ll = long long;
const ll INF = 1e18;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

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

    int S, T, U, V;
    cin >> S >> T >> U >> V;

    vector<vector<pair<int, ll>>> adj(N + 1);
    for (int i = 0; i < M; i++) {
        int u, v;
        ll w;
        cin >> u >> v >> w;
        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
    }

    // Lambda for Dijkstra
    auto run_dijkstra = [&](int start, vector<ll>& dist) {
        dist.assign(N + 1, INF);
        dist[start] = 0;
        priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<>> pq;
        pq.push({0, start});

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

            if (d > dist[u]) continue;

            for (const auto& [v, w] : adj[u]) {
                if (dist[u] + w < dist[v]) {
                    dist[v] = dist[u] + w;
                    pq.push({dist[v], v});
                }
            }
        }
    };

    vector<ll> distS, distT, distU, distV;
    run_dijkstra(S, distS);
    run_dijkstra(T, distT);
    run_dijkstra(U, distU);
    run_dijkstra(V, distV);

    vector<bool> visited(N + 1, false);
    vector<ll> dpU(N + 1, INF);
    vector<ll> dpV(N + 1, INF);
    
    // Initial answer is just the raw U -> V cost without the commuter pass
    ll ans = distU[V];

    // Lambda for our Memoized DFS
    // Explicitly defining the return type as void, and we use a recursive lambda using auto& self
    auto dfs = [&](auto& self, int u) -> void {
        if (visited[u]) return; // Memoization: Don't recalculate
        visited[u] = true;
        
        // Base state: the node itself
        dpU[u] = distU[u];
        dpV[u] = distV[u];

        for (const auto& [v, w] : adj[u]) {
            // Check if moving u -> v is progressing along a shortest path to T
            if (distS[u] + w + distT[v] == distS[T]) {
                self(self, v); // Recurse down the DAG
                
                // Bring the minimums up from the children
                dpU[u] = min(dpU[u], dpU[v]);
                dpV[u] = min(dpV[u], dpV[v]);
            }
        }

        // Calculate the answer for this specific sub-path overlap
        // 1. Enter from U at 'u', leave towards V at some descendant
        ans = min(ans, distU[u] + dpV[u]); 
        
        // 2. Enter from V at 'u', leave towards U at some descendant
        ans = min(ans, distV[u] + dpU[u]); 
    };

    // Kick off the DFS from the start of the commuter pass
    dfs(dfs, S);

    cout << ans << "\n";
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...