题目大意:
\(n\) 个点每个点有一个点权,依据点权的大小关系确定 \(m\) 条边权,求最长路。
思路:
关于SPFA,他死了。
很明显是求带负权的最长路,赛后有数据毙掉SPFA,考虑如何转化边权使得可以用 dijkstra 求解。
我们将点权看作势能,加入到最短路的求解中。
设原边权为 \(w(u, v)\),新边权为 \(\bar{w}(u, v)=w(u, v)+h[u]-h[v]\)。
假设最短路径为 1-->2-->3-->4,
那么新的最短路径为
\[\begin{array}{l}
\bar{w}(1,2)+\bar{w}(2,3)+\bar{w}(3,4) \\
=w(1,2)+h[1]-h[2]+w(2,3)+h[2]-h[3]+w(3,4)+h[3]-h[4] \\
=w(1,2)+w(2,3)+w(3,4)+h[1]-h[4]
\end{array}
\]
可以看到,新的最短路径只与起点和终点的势能有关。
考虑这样转化后的边权。
记取反后的边权为 \(\tilde{w}(u, v)\)
如果 \(h[u] > h[v]\):
\(w(u, y) = h[u] - h[v]\)
\(\tilde{w}(u, y) = h[v] - h[u]\)
\(\bar{w}(u, v) = h[v] - h[u] + h[u] - h[v] = 0\)
如果 \(h[u] < h[v]\):
\(w(u, y) = -2(h[v] - h[u])\)
\(\tilde{w}(u, y) = 2(h[v] - h[u])\)
\(\bar{w}(u, v) = 2(h[v] - h[u]) + h[u] - h[v] = h[v] - h[u] > 0\)
这样,边权加入了势能后就都是非负的,可以运用 dijstra 求最长路。
具体的,得到的答案 \(dis[u]\) 减去势能 \(h[1] - h[u]\),再取反得到最长路,即 \(-(dis[u] - (h[1] - h[u]))\)。
Code:
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, m;
cin >> n >> m;
vector<int> h(n + 1);
for (int i = 1; i <= n; i++) {
cin >> h[i];
}
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
if (h[u] > h[v]) {
addedge(u, v, 0);
addedge(v, u, h[u] - h[v]);
} else if (h[u] == h[v]) {
addedge(u, v, 0);
addedge(v, u, 0);
} else {
addedge(v, u, 0);
addedge(u, v, h[v] - h[u]);
}
}
dijkstra(n, 1);
ll ans = 0;
for (int u = 1; u <= n; u++) {
if (dis[u] == INF)
continue;
ans = max(ans, -(dis[u] - (h[1] - h[u])));
}
cout << ans << "\n";
return 0;
}