Submission #1187904

#TimeUsernameProblemLanguageResultExecution timeMemory
1187904patgraOlympic Bus (JOI20_ho_t4)C++20
100 / 100
247 ms9884 KiB
#include <bits/stdc++.h>

#define rep(a,b,c) for(auto a = (b); a != (c); a++)
#define repD(a,b,c) for(auto a = (b); a != (c); a--)
#define repIn(a, b) for(auto& a : (b))
#define repIn2(a, b, c) for(auto& [a, b] : (c))

constexpr bool dbg = 0;
#define DEBUG if constexpr(dbg)
#define DC DEBUG std::cerr
#define eol std::endl

#define ll long long
#define pb push_back
#define int ll

using namespace std;

constexpr int inf = 1e18 + 7;
int n, m;
vector<array<int, 4>> edges;
vector<pair<int, int>> whichEdge;
vector<vector<pair<int, int>>> g, gR;
vector<vector<vector<int>>> dist; // from 1, from N, to 1, to N
vector<vector<vector<int>>> minPref, minSuf;

void calcDistWithout(int X, int S, int which, bool rev) {
    vector<bool> vis(n + 1, 0);
    rep(i, 1, n + 1) dist[which][X][i] = inf;
    dist[which][X][S] = 0;
    int squirt = (int)sqrt(n);
    vector<pair<int, int>> sqAr((n + 1) / squirt + 1, {inf, inf});
    sqAr[S / squirt] = {0, S};
    while(true) {
        pair<int, int> minDist = {inf, inf};
        repIn(i, sqAr) minDist = min(minDist, i);
        auto [ds, v] = minDist;
        if(ds == inf) break;
        vis[v] = true;
        sqAr[v / squirt] = {inf, inf};
        int mysq = v / squirt;
        rep(i, mysq * squirt, min(mysq * squirt + squirt, n + 1)) if(!vis[i]) sqAr[mysq] = min(sqAr[mysq], {dist[which][X][i], i});
        if(v == X) continue;
        repIn2(u, d, (rev ? gR : g)[v]) if(!vis[u]) dist[which][X][u] = min(dist[which][X][u], ds + d), sqAr[u / squirt] = min(sqAr[u / squirt], {ds + d, u});
    }
}

int32_t main() {
    ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> m;
    edges.resize(m);
    whichEdge.resize(m);
    g.resize(n + 1);gR.resize(n + 1);
    dist.resize(4, vector<vector<int>>(n + 1, vector<int>(n + 1)));
    minPref.resize(4, vector<vector<int>>(n + 1));
    minSuf.resize(4, vector<vector<int>>(n + 1));
    rep(i, 0, m) {
        int v, u, c1, c2;
        cin >> v >> u >> c1 >> c2;
        edges[i] = {v, u, c1, c2};
        whichEdge[i] = {g[v].size(), gR[u].size()};
        g[v].pb({u, c1});
        gR[u].pb({v, c1});
    }
    
    rep(i, 1, n + 1) calcDistWithout(i, 1, 0, 0);
    rep(i, 1, n + 1) calcDistWithout(i, n, 1, 0);
    rep(i, 1, n + 1) calcDistWithout(i, 1, 2, 1);
    rep(i, 1, n + 1) calcDistWithout(i, n, 3, 1);
    DEBUG {
        DC << "Dist from 1: " << eol;
        rep(i, 1, n + 1) {
            DC << " without " << i << ": " << eol;
            rep(j, 1, n + 1) DC << "  (" << j << "): " << dist[0][i][j] << eol;
        }
        DC << "Dist from N: " << eol;
        rep(i, 1, n + 1) {
            DC << " without " << i << ": " << eol;
            rep(j, 1, n + 1) DC << "  (" << j << "): " << dist[1][i][j] << eol;
        }
        DC << "Dist to 1: " << eol;
        rep(i, 1, n + 1) {
            DC << " without " << i << ": " << eol;
            rep(j, 1, n + 1) DC << "  (" << j << "): " << dist[2][i][j] << eol;
        }
        DC << "Dist to N: " << eol;
        rep(i, 1, n + 1) {
            DC << " without " << i << ": " << eol;
            rep(j, 1, n + 1) DC << "  (" << j << "): " << dist[3][i][j] << eol;
        }
    }

    rep(which, 0, 4) rep(v, 1, n + 1) { 
        minPref[which][v].resize(g[v].size());
        int mp = inf;
        int i = 0;
        repIn2(u, c, g[v]) { 
            mp = min(mp, c + dist[which][v][u]);
            minPref[which][v][i++] = mp;
        }
    }
    rep(which, 0, 4) rep(v, 1, n + 1) {
        minSuf[which][v].resize(g[v].size());
        int mp = inf;
        int i = (int)g[v].size() - 1;
        ranges::reverse(g[v]);
        repIn2(u, c, g[v]) { 
            mp = min(mp, c + dist[which][v][u]);
            minSuf[which][v][i--] = mp;
        }
        ranges::reverse(g[v]);
    }

    int ans = min(inf, dist[0][n][n] + dist[1][1][1]);
    DC << "if we reverse nothing ans = " << ans << eol;
    int i = 0;
    for(auto [v, u, c1, c2] : edges) {
        auto [ii, ir] = whichEdge[i];
        int toN = min(dist[0][v][n], dist[0][v][v] + min((ii ? minPref[3][v][ii - 1] : inf), (ii < (int)g[v].size() - 1 ? minSuf[3][v][ii + 1] : inf)));
        toN = min(toN, dist[0][v][u] + c1 + dist[3][u][v]);
        int fromN = min(dist[1][v][1], dist[1][v][v] + min((ii ? minPref[2][v][ii - 1] : inf), (ii < (int)g[v].size() - 1 ? minSuf[2][v][ii + 1] : inf)));
        fromN = min(fromN, dist[1][v][u] + c1 + dist[2][u][v]);
        DC << "if we reverse edge " << i << " ans = " << toN + fromN + c2 << eol;
        ans = min(ans, toN + fromN + c2);
        i++;
    }

    cout << (ans == inf ? -1 : ans) << '\n';
}

#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...