TIOJ-1706

遞給了你一張地圖,跟你解釋著:
這張地圖上面標示了許多連接城與城之間的雙向道路。每條道路上都有一座收費站。每
座收費站每個方向(沒錯,同一個收費站不同方向過路費也會不一樣)都有一個起始過路費C ,
在第一天時收費就是C元。但是還有一個費用變量P,每一天結束在下一天開始之前,
會把該方向過路費調整P元(正表示過路費調昇、負表示調降)。
也就是說,第T天的費用為C+(T-1)×P。
你們已經調查出了國王居住的城市跟皇后居住的城市,
而且知道國王一定會在[1,D](包含1 和 D)的某一天去拜訪皇后再在當日回到國王城市。
國王嗜錢如命,自然希望這一趟旅行過路費儘量少。
請你輸出國王選了最划算的日子拜訪皇后之下,所需要支付的總過路費。

$N, M\le 10^5, D\le 10^4, 0\le C_i+(D-1)P_i \le 10^4$。


一個直覺地解就是枚舉每一天數,然後就能去計算最短路徑(起點做單點源,終點也做單點源,然後就能知道來回的距離)。
但是這樣會TLE,觀察到在第t天對於每一條路徑的過路費總和為
$$\sum^i_{i\in path} (c_i+(t-1)p_i)=\sum^i_{i\in path}c_i+(t-1)\sum^i_{i\in path}p_i$$
後面那項$p_i$總和如果是負數,那就最好在第一天就出門,否則t越大越好(在最後一天出門)。
因此只要枚舉第一天和最後一天取答案較小值。
複雜度$\mathcal{O}(ElogE)$

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
/*
-------------- | /
| | /
| | /
| * |/ | | ------ *
| | | | / \
| | |\ | | | |\ |
\ | | | \ | | | | \ |
\ | | | \ | | \ / \ |
V | | \ \__/| ----- \ |
*/
#include <bits/stdc++.h>
using namespace std;

#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL);
#define mem(i,j) memset(i,j,sizeof (i));
using ll = int64_t;
using ull = uint64_t;
using ld = long double;
using uint = uint32_t;
const double EPS = 1e-8;
const int INF = 0x3F3F3F3F;
const ll LINF = 4611686018427387903;
const int MOD = 1e9+7;
/*-----------------------------------------------------------------------------------------------------*/

struct edg {
int v, c, p;
};

signed main() {
EmiliaMyWife

int n, m, a, b, d;
cin >> n >> m >> a >> b >> d;
vector<vector<edg>> edge(n + 1);
for(int i = 0, x, y, a, b, c, p; i < m; i++)
cin >> x >> y >> a >> b >> c >> p, edge[x].push_back({y, a, b}), edge[y].push_back({x, c, p});
vector<int> dis, dis2;
auto dijkstra = [&](int a, vector<int> &dis, int d) {
dis = vector<int>(n + 1, INF);
dis[a] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, a});
while(!pq.empty()) {
auto [c, u] = pq.top();
pq.pop();
if(dis[u] < c)
continue;
for(auto &x : edge[u]) {
int cost = x.c + x.p * d;
if(c + cost < dis[x.v]) {
dis[x.v] = c + cost;
pq.push({dis[x.v], x.v});
}
}
}
};
dijkstra(a, dis, 0), dijkstra(b, dis2, 0);
int ans = dis[b] + dis2[a];
dijkstra(a, dis, d - 1), dijkstra(b, dis2, d - 1);
cout << min(ans, dis[b] + dis2[a]) << '\n';

return 0;
}