【BZOJ2200】道路与航线

题目链接:https://www.acwing.com/problem/content/344/

题目大意:给定一张有向图 , 其中可分为若干个连通块 , 每个连通块内的道路均为双向 , 且权值为正 , 联通块间的道路为单向 , 权值可为负数 , 这若干个连通块组成一个DAG , 求起点 \(s\) 到各个节点的最短路径

solution

显然这是一个单元最短路模板 , 但边权有为负 , 用SPFA会被卡掉 , 但可以利用题目中的一些性质来解决

对于每个连通块内 , 可以用dijstra来求出点之间的最短路径 , 连通块之间由于构成了一个DAG , 可以用拓扑来求最短路径

具体地 , 可以构建一个队列 , 每次加入总入度为 0 的联通块 , 每次取出队首的连通块 , 在块内跑dijstra , 与此同时把这个连通块所相邻的各个连通块的总入度减去 1 , 若发现入度减为 0 , 则把这个连通块入队

复杂度 : \(O(mlogn)\)

code

#include<bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &FF) {
    int RR = 1; FF = 0; char CH = getchar();
    for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    FF *= RR;
}
inline void file(string str) {
    freopen((str + ".in").c_str(), "r", stdin);
    freopen((str + ".out").c_str(), "w", stdout);
}
const int N = 5e5 + 10;
int si, now, vis[N], fst[N], nxt[N], num[N], wi[N], n, x, y, s, rd[N];
void add(int u, int v, int w) {
    nxt[++now] = fst[u], fst[u] = now, num[now] = v, wi[now] = w;
}
void dfs(int xi) {
    for(int i = fst[xi]; i; i = nxt[i])
        if(!vis[num[i]])
            vis[num[i]] = vis[xi], dfs(num[i]);
}
int st[N], bk[N]; queue<int> q;
void dijstra(int xi) {
    priority_queue<pair<int, int> > qi;
    for(int i = 1; i <= n; i++)
        if(vis[i] == xi)
            qi.push(make_pair(-st[i], i));
    while(!qi.empty()) {
        int pi = qi.top().second; qi.pop();
        if(bk[pi]) continue; bk[pi] = true;
        for(int i = fst[pi]; i; i = nxt[i]) {
            if(st[pi] + wi[i] < st[num[i]]) {
                st[num[i]] = st[pi] + wi[i];
                if(vis[pi] == vis[num[i]])
                    qi.push(make_pair(-st[num[i]], num[i]));
            }
            if(vis[pi] != vis[num[i]]) {
                rd[vis[num[i]]]--;
                if(!rd[vis[num[i]]]) q.push(vis[num[i]]);
            }
        }
    }
}
int main() {
    //file("");
    int u, v, w;
    read(n), read(x), read(y), read(s);
    for(int i = 1; i <= x; i++)
        read(u), read(v), read(w), add(u, v, w), add(v, u, w);
    for(int i = 1; i <= n; i++)
        if(!vis[i]) vis[i] = ++si, dfs(i);
    for(int i = 1; i <= y; i++) {
        read(u), read(v), read(w), add(u, v, w);
        rd[vis[v]]++;
    }
    memset(st, 0x3f, sizeof(st)); st[s] = 0;
    for(int i = 1; i <= si; i++)
        if(rd[i] == 0) q.push(i);
    //if(rd[vis[s]]) q.push(vis[s]);
    while(!q.empty()) {
        int pi = q.front(); q.pop();
        dijstra(pi);
    }
    for(int i = 1; i <= n; i++)
        if(st[i] >= 1e9) puts("NO PATH");
        else cout << st[i] << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/magicduck/p/12240858.html