疫情延遲 題解

_zqh發表於2024-10-14

關於 SPFA,
它還苟延殘喘地活著……

題意

一個無向圖,每條邊有兩個權 \(x, y\),求能否透過刪除一些邊使得 \(x\) 的最短路 \(1 \to n\) 不小於 \(T\),輸出刪除的邊的 \(y\) 的最大值的最小值。

題解

觀察到如果我們列舉一個 \(y\) 的最大值 \(k\),我們就可以刪掉所有 \(y \le k\) 的邊(不要錢,不刪白不刪)。

跑 spfa 就行啦。

但是會超時!洗洗睡吧

觀察到題目要求是“最大值最小”,不難想到可以二分 \(k\)

因為我 \(k\) 增加,對應要刪的邊增加,刪掉的邊越多最短路越大,一定滿足單調性。

不會超時啦!

一個二分的複雜度 \(\log m\),spfa 的抽象時間複雜度 \(mk\)

\(k\) 是一個由 \(1\)\(n\) 不等的《小》常數(取決於資料強度)。

時間複雜度:\(\mathcal O(mk \log m)\),抽象但是反正能過。

namespace zqh {
const int N = 20005;

int n, m, T;
int dis[N];
bool vis[N];

struct node {
    int to;
    int tim;
    int year;
};

struct edge {
    int u, v;
    int tim, year;
};

bool operator<(edge x, edge y) {
    return x.year < y.year;
}

vector<node> g[N];
vector<edge> e;

void spfa(int s, int jq) {
    memset(dis, 0x3f, sizeof(dis));
    dis[s] = 0;
    queue<int> q;
    q.push(s);
    vis[s] = true;
    while (q.size()) {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for (auto [v, t, y] : g[u]) {
            if (y <= jq)
                continue;
            if (dis[v] > dis[u] + t) {
                dis[v] = dis[u] + t;
                if (!vis[v])
                    q.push(v), vis[v] = true;
            }
        }
    }
}

void init() {
    cin >> n >> m >> T;
    for (int i = 1; i <= m; i++) {
        int u, v, t, y;
        cin >> u >> v >> t >> y;
        e.push_back({u, v, t, y});
    }
    sort(e.begin(), e.end());
    for (int i = 0; i < m; i++) {
        g[e[i].u].push_back({e[i].v, e[i].tim, e[i].year});
    }
}

void solve() {
    spfa(1, LLONG_MIN);
    if (dis[n] >= T) {
        cout << "-1 " << dis[n];
        return;
    }
    int l = 1, r = m, ans = 0;
    while (l <= r) {
        int mid = (l + r) >> 1;
        spfa(1, e[mid - 1].year);
        if (dis[n] >= T) {
            r = mid - 1;
            ans = mid;
        } else
            l = mid + 1;
    }
    cout << e[ans - 1].year;
}

void main() {
    init();
    solve();
}
}  // namespace zqh

相關文章