CF1715E ELong Way Home

最短路

1.CF1715 ELong Way Home

题目描述

nn 座城市,城市间有 mm 条双向道路,通过第 ii 条道路需要花费 wiw_i 的时间,任意两个城市之间都有航班,乘坐城市 uuvv 之间的航班需要花费 (uv)2(u-v)^2 的时间。

现在请对于任意城市 i(1in)i(1 \le i \le n),求出从城市 11 出发,到达城市 ii 所需要的最短时间,注意从城市 11ii 的过程中最多乘坐 kk 次航班

题目分析

看到平方直接一眼dp,但是发现还有地上的道路,所以要跑一跑dij,然后 由于每个点可以从所有点转移过来,所以先预处理出一个凸壳,然后利用斜率的单调性进行斜率优化,更新一下时间,然后再放缩一遍。因为最多做k次放缩,所以总的时间复杂度为O(k(n+mlogn))O(k(n+mlogn))

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
//
// Created by mrx on 2022/9/29.
//
#include <vector>
#include <algorithm>
#include <iostream>
#include <array>
#include <queue>

using ll = long long;

struct line {
ll k, b;

line(ll k, ll b) : k(k), b(b) {}

double intersect(const line& l) const { return 1.0 * (l.b - b) / (k - l.k); }

bool operator <(const line& rhs) const {
if (k == rhs.k) return b > rhs.b;
return k < rhs.k;
}

ll operator ()(ll x) const { return k * x + b; }
};

struct ConvexHull {
std::vector<double> points;
std::vector<line> lines;

int size() { return points.size(); }

void reset() {
points.clear();
lines.clear();
}

void init(const line& l) {
points.push_back(-1e9);
lines.push_back(l);
}

void addLine(const line& l) {
if (points.size() == 0) {
points.push_back(-1e9);
lines.push_back(l);
return;
}
while (lines.size() >= 2 && l.intersect(lines[lines.size() - 2]) <= points.back()) {
points.pop_back();
lines.pop_back();
}
points.push_back(l.intersect(lines.back()));
lines.push_back(l);
}

ll query(int x, int id) { return lines[id](x); }

ll query(int x) {
int id = upper_bound(points.begin(), points.end(), x) - points.begin() - 1;
return lines[id](x);
}
};

int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);

int n, m, k;
std::cin >> n >> m >> k;

std::vector<std::vector<std::pair<int, ll>>> adj(n);
for (int i = 0; i < m; ++i) {
int u, v;
ll w;
std::cin >> u >> v >> w;
u--, v--;
adj[u].emplace_back(v, w);
adj[v].emplace_back(u, w);
}

std::vector<ll> dis(n, 0x3f3f3f3f3f3f3f3f);
std::function<void(const std::vector<int>&)> dijkstra = [&](const std::vector<int>& start) {
std::priority_queue<std::pair<ll, int>, std::vector<std::pair<ll, int>>, std::greater<>> q;
for (auto i: start)q.emplace(dis[i], i);
while (!q.empty()) {
auto [dist, u] = q.top();
q.pop();
if (dis[u] != dist)continue;
for (auto [v, w]: adj[u]) {
if (w + dis[u] < dis[v]) {
dis[v] = w + dis[u];
q.emplace(dis[v], v);
}
}
}
};

dis[0] = 0;
dijkstra((std::vector<int>(1)));

for (int i = 0; i < k; ++i) {
ConvexHull ch;
std::vector<int> change;
for (ll j = 0; j < n; ++j) {
ch.addLine(line(-2 * j, dis[j] + j * j));
}
int id = 0;
for (ll u = 1; u < n; u++) {
while (id + 1 < ch.size() && ch.query(u, id + 1) < ch.query(u, id)) id++;
ll cur = ch.query(u, id) + ll(u) * u;
if (cur < dis[u]) {
change.push_back(u);
dis[u] = cur;
}
}
dijkstra(change);
}
for (int i = 0; i < n; ++i)std::cout << dis[i] << " \n"[i == n - 1];
return 0;
}

CF1715E ELong Way Home
https://mrxyan6.github.io/2022/09/29/CF1715E/
作者
mrx
发布于
2022年9月29日
许可协议