拓扑排序 + 最短路。

Table of Contents

  1. Description
  2. Solution

Description

有一些正权双向边和边权可能为负的单向边, 保证没有负环. 求最短路, 且不能使用SPFA.

Solution

不能使用SPFA就只能用Dijkstra了, 但是她不能处理负权边, 注意到没有负环, 也就是把图缩点后一定是负权边在DAG上转移, 假如我们每次只做联通块内的点, Dijkstra是没有影响的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>

using namespace std;

const int maxn = 25005;
const int maxm = 100005;

struct edge
{
int to, nxt, v;
}e[maxm << 1], ce[maxm];
struct node
{
int d, id;
node(int d_ = 0, int i_ = 0):d(d_),id(i_){}
bool operator < (const node &rhs) const {
return d > rhs.d;
}
};
int cptr, clnk[maxn];
int ptr, t, lnk[maxn], dis[maxn], n, m1, m2, s, dgr[maxn];
int dfn[maxn], cnt, num, bel[maxn], low[maxn], vis[maxn];
stack<int> st;
vector<int> vec[maxn];

inline int rd() {
register int x = 0, f = 0, c = getchar();
while (!isdigit(c)) {
if (c == '-') f = 1;
c = getchar();
}
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return f ? -x : x;
}
inline void add(int bgn, int end, int val) {
e[++ptr] = (edge){end, lnk[bgn], val};
lnk[bgn] = ptr;
}
inline void cadd(int bgn, int end, int val) {
ce[++cptr] = (edge){end, clnk[bgn], val};
clnk[bgn] = cptr;
}
void tarjan(int x) {
dfn[x] = low[x] = ++cnt;
vis[x] = 1;
st.push(x);
for (int p = lnk[x]; p; p = e[p].nxt) {
int y = e[p].to;
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
} else if (vis[y]) {
low[x] = min(low[x], dfn[y]);
}
}
if (dfn[x] == low[x]) {
int now; num++;
do {
now = st.top(); st.pop();
bel[now] = num; vec[num].push_back(now);
vis[now] = 0;
} while (now != x);
}
}
void dijkstra(int x) {
priority_queue<node> q;
for (vector<int>::iterator iter = vec[x].begin(); iter != vec[x].end(); ++iter)
if (dis[*iter] < 0x3f3f3f3f) q.push(node(dis[*iter], *iter));
while (!q.empty()) {
node u = q.top(); q.pop();
if (vis[u.id]) continue;
vis[u.id] = 1;
for (int p = lnk[u.id]; p; p = e[p].nxt) {
int y = e[p].to;
if (dis[y] > dis[u.id] + e[p].v) {
dis[y] = dis[u.id] + e[p].v;
if (bel[u.id] != bel[y]) continue;
q.push(node(dis[y], y));
}
}
}
}
void toposort() {
queue<int> q;
for (int i = 1; i <= num; ++i)
if (!dgr[i]) q.push(i);
while (!q.empty()) {
int u = q.front(); q.pop();
dijkstra(u);
for (int p = clnk[u]; p; p = ce[p].nxt) {
int y = ce[p].to;
if (!--dgr[y]) q.push(y);
}
}
}


int main() {
n = rd(); m1 = rd(); m2 = rd(); s = rd();
int u, v, w;
memset(dis, 0x3f, sizeof dis);
dis[s] = 0;
for (int i = 1; i <= m1; ++i) {
u = rd(); v = rd(); w = rd();
add(u, v, w);
add(v, u, w);
}
for (int i = 1; i <= m2; ++i) {
u = rd(); v = rd(); w = rd();
add(u, v, w);
}
for (int i = 1; i <= n; ++i)
if (!dfn[i]) tarjan(i);
for (int i = 1; i <= n; ++i) {
for (int p = lnk[i]; p; p = e[p].nxt) {
int y = e[p].to;
if (bel[i] != bel[y])
cadd(bel[i], bel[y], e[p].v), ++dgr[bel[y]];
}
}
toposort();
for (int i = 1; i <= n; ++i) {
if (dis[i] < 0x3f3f3f3f) printf("%d\n", dis[i]);
else puts("NO PATH");
}
return 0;
}