道路与航线
\(topsort + dijkstra\)
\(有负边,但spfa已死.\)
\(由题意,图中会有很多块,每个块之间是航路(单向边),块内部是道路(双向边).\\所以我们用拓扑序的顺序对每个块做Djk就可以了.保证了正确性和时间.\)
#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
inline int lowbit(int x) { return x & (-x); }
#define ll long long
#define ull unsigned long long
#define pb push_back
#define PII pair<int, int>
#define VIT vector<int>
#define x first
#define y second
#define inf 0x3f3f3f3f
const int N = 25010, M = 150010;
int h[N], ne[M], w[M], e[M], idx;
int d[N];
bool st[N];
int n, m1, m2, S;
int id[N], cnt;
int din[N];
vector<int> blo[N];
queue<int> q;
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void dfs(int u, int bid) {
id[u] = bid;
blo[bid].pb(u);
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (!id[j]) dfs(j, bid);
}
}
void show_block() {
cout << cnt << '\n';
for (int i = 1; i <= cnt; ++i) {
for (int j : blo[i]) cout << j << ' ';
cout << '\n';
}
}
void dijkstra(int bid) {
priority_queue<PII, vector<PII>, greater<PII>> pq;
for (auto i : blo[bid]) pq.push({d[i], i});
while (pq.size()) {
PII t = pq.top();
pq.pop();
int ver = t.y, dis = t.x;
if (st[ver]) continue;
st[ver] = 1;
for (int i = h[ver]; ~i; i = ne[i]) {
int j = e[i];
if (id[j] != id[ver] && --din[id[j]] == 0) q.push(id[j]);
if (d[j] > dis + w[i]) {
d[j] = dis + w[i];
if (id[j] == id[ver]) pq.push({d[j], j});
}
}
}
}
void topsort() {
memset(d, 0x3f, sizeof d);
d[S] = 0;
for (int i = 1; i <= cnt; ++i)
if (!din[i]) q.push(i);
while (q.size()) {
int t = q.front();
q.pop();
dijkstra(t);
}
}
int main() {
IO;
//freopen("in.txt", "r", stdin);
memset(h, -1, sizeof h);
cin >> n >> m1 >> m2 >> S;
while (m1--) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
for (int i = 1; i <= n; ++i)
if (!id[i]) dfs(i, ++cnt);
while (m2--) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
din[id[b]]++;
}
topsort();
for (int i = 1; i <= n; ++i)
if (d[i] > inf / 2) cout << "NO PATH\n";
else cout << d[i] << '\n';
return 0;
}