疫情延迟 题解

关于 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

但在我的心中,它已经死了……

posted @ 2024-10-14 22:56  Reveriean  阅读(14)  评论(0)    收藏  举报