洛谷 - P1462 - 通往奥格瑞玛的道路 - 二分 - Dijkstra

https://www.luogu.org/problem/P1462

感觉,要二分最大收费权的城市,把小于等于它的全部插进去,Dijkstra一下求出最小的血量。这样感觉太暴力了。

考虑只有10000个城市,sort一下,每条无向边都由排名靠后的城市插入。按收费顺序插入城市,直到并查集中1和n连通,来一次Dijkstra求出所需的血量。

假如所需血量已经>=b,说明不合法。

这个时候插入下一个城市及其连通的边,考虑会发生什么改变?首先到达这个城市的最短距离必定是从连出城市走对应路径过来的。

其次它可能会对整个图进行一次更新。所以这个复杂度也是惊人。

所以还是二分城市,要log1e5=15,插入对应的边5e4,跑一次Dijkstra要5e4log5e4=8e5,小得很。


想着至少要过一半吧,没想到一发就全AC了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e4 + 5, INF = 0x3f3f3f3f;

struct Edge {
    int v, w;
    Edge() {}
    Edge(int v, int w): v(v), w(w) {}
};
bool vis[MAXN];
int dis[MAXN];
vector<Edge> G[MAXN];

int fa[MAXN];
int find(int x) {
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}

void merge(int x, int y) {
    int fx = find(x), fy = find(y);
    fa[fy] = fx;
}

struct City {
    int id, f;
    bool operator<(const City &c)const {
        return f < c.f;
    }
} city[MAXN];

int n, b;

void Init() {
    for(int i = 0; i <= n; ++i)
        fa[i] = i;
    memset(vis, 1, sizeof(vis[0]) * (n + 1));
    memset(dis, INF, sizeof(dis[0]) * (n + 1));
}

void AddCity(int Ceil) {
    for(int i = 1; i <= Ceil; ++i) {
        int u = city[i].id;
        vis[u] = 0;
        for(auto ei : G[u])
            merge(u, ei.v);
    }
}

priority_queue<pair<int, int> > pq;
int Dijkstra(int s) {
    pq.push({0, 1});
    dis[1] = 0;
    while(!pq.empty()) {
        int u = pq.top().second;
        pq.pop();
        if(vis[u])
            continue;
        vis[u] = 1;
        for(auto ei : G[u]) {
            int v = ei.v, w = ei.w;
            if(!vis[v] && dis[u] + w < dis[v]) {
                dis[v] = dis[u] + w;
                pq.push({-dis[v], v});
            }
        }
    }
    return dis[n];
}

bool check(int Ceil) {
    Init();
    AddCity(Ceil);
    if(find(1) != find(n))
        return false;
    int res = Dijkstra(1);
    return res < b;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int m;
    scanf("%d%d%d", &n, &m, &b);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &city[i].f);
        city[i].id = i;
    }
    sort(city + 1, city + 1 + n);
    for(int i = 1; i <= m; ++i) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        G[u].emplace_back(Edge(v, w));
        G[v].emplace_back(Edge(u, w));
    }
    int L = 1, R = n, M;
    while(1) {
        M = L + R >> 1;
        if(L == M) {
            if(check(L)) {
                printf("%d\n", city[L].f);
                return 0;
            } else if(check(R)) {
                printf("%d\n", city[R].f);
                return 0;
            }
            puts("AFK");
            return 0;
        }
        if(check(M))
            R = M;
        else
            L = M + 1;
    }
}
posted @ 2019-08-13 03:59  韵意  阅读(167)  评论(0编辑  收藏  举报