我大概是应该反省一下我的做题思路了。
k
=
0
k=0
k=0,直接一发
d
i
j
k
s
t
r
a
dijkstra
dijkstra结束
k
=
1
k=1
k=1,做一发
d
i
j
k
s
t
r
a
dijkstra
dijkstra,然后考虑用航线来进行更新。推一下式子发现就是个斜率优化,根据第一轮
d
i
j
k
s
t
r
a
dijkstra
dijkstra的结果来维护一个凸壳,每次二分查找最优值进行更新就行。最后再跑一遍最短路完事儿。
k
≥
2
k \ge 2
k≥2的情况类似。
关于为什么没能在考场上做出来:我根本没意识到这就是个斜率优化,还在推数学性质呢…只能说知识点不熟吧(悲
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 1e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int N, M, K;
int dis[MAXN];
vector<int> G[MAXN], W[MAXN];
struct node {
int u, dis;
node(int a = 0, int b = 0) {
u = a;
dis = b;
}
friend bool operator<(node a, node b) {
return a.dis > b.dis;
}
};
void dijkstra() {
static bool vis[MAXN];
priority_queue<node> Q;
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= N; i++)
Q.push(node(i, dis[i]));
while (Q.size()) {
int u = Q.top().u;
Q.pop();
if (vis[u]) continue;
vis[u] = true;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
int w = W[u][i];
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
Q.push(node(v, dis[v]));
}
}
}
}
double slope(int i, int j) {
return 1.0 * ((dis[j] + j * j) - (dis[i] + i * i)) / (j - i);
}
void convex_hull_trick() {
vector<int> convex;
static int tmp[MAXN];
for (int i = 1; i <= N; i++) {
while (convex.size() >= 2 &&
slope(i, *convex.rbegin()) <
slope(*(convex.rbegin() + 1), *convex.rbegin()))
convex.pop_back();
convex.push_back(i);
}
for (int i = 1; i <= N; i++) {
int l = 0, r = convex.size() - 1, j;
while (l <= r) {
int m = (l + r) >> 1;
double lslope = (m == 0 ? -inf : slope(convex[m - 1], convex[m]));
// int rslope = (m + 1 == convex.size() ? -inf : slope(convex[m],
// convex[m + 1]));
if (lslope <= 2 * i) {
j = convex[m];
l = m + 1;
} else
r = m - 1;
}
tmp[i] = min(dis[i], dis[j] + (j - i) * (j - i));
}
for (int i = 1; i <= N; i++)
dis[i] = tmp[i];
}
signed main() {
freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false);
cin >> N >> M >> K;
for (int i = 1; i <= N; i++)
dis[i] = inf;
dis[1] = 0;
for (int i = 1, u, v, w; i <= M; i++) {
cin >> u >> v >> w;
G[u].push_back(v);
G[v].push_back(u);
W[u].push_back(w);
W[v].push_back(w);
}
while (K--) {
dijkstra();
convex_hull_trick();
}
dijkstra();
for (int i = 1; i <= N; i++)
cout << dis[i] << " ";
return 0;
}