第K大的尽量小,这种表述就容易让人想到二分。

蓝书上的解释:因为支付的钱更多时,合法的升级方案一定有包含子花费更少的升级方案,所以答案具有单调性。

那么我们只要把权值大于mid的路径权值设为1,小于mid的置为0,求1到n的最短路是否不超过n即可。

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#pragma GCC optimize(2)

using namespace std;
typedef long long LL;
typedef pair<LL, int> PII;


const int N = 2e4 + 5, mod = 1e9 + 9, INF = 0x3f3f3f3f;
int e[N], h[N], ne[N], w[N], d[N];
int n, p, k, idx, ans;
bool vis[N];

priority_queue< PII, vector<PII>, greater<PII> > q;

void init() {
    memset(h, -1, sizeof h);
    memset(d, 0x3f, sizeof d);
    memset(vis, false, sizeof vis);
}

void add(int a, int b, int c) {
    e[idx] = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a] = idx++;
    return ;
}

int dij(int mid) {
    memset(d, 0x3f, sizeof d);
    memset(vis, false, sizeof vis);
    d[1] = 0;
    q.push(make_pair(0, 1));

    while (!q.empty()) {
        int x = q.top().second;
        q.pop();
        if (vis[x]) continue;
        else vis[x] = 1;

        for (int i = h[x]; i != -1; i = ne[i]) {
            int y = e[i], z = w[i];

            if (z > mid) z = 1;
            else z = 0;

            if (d[x] + z < d[y]) {
                d[y] = d[x] + z;
                q.push(make_pair(d[y], y));
            }
        }
    }
    return d[n];
}

int main()
{
    init();
    cin >> n >> p >> k;
    int ed = -INF;
    while (p--) {
        int x, y, z;
        cin >> x >> y >> z;
        add(x, y, z);
        add(y, x, z);
        ed = max(ed, z);
    }


    if(dij(0) == INF) {
        printf("-1\n");
    } else {
        int ll = 0, rr = ed;
        int mid;
        while (ll <= rr) {
//            cout << rr << endl;
            int mid = (ll + rr) / 2;
            if (dij(mid) <= k) {
                ans = mid;
                rr = mid - 1;
            } else {
                ll = mid + 1;
            }
        }
        cout << ans << endl;
    }

}
02-11 06:10