题解:P14019 [ICPC 2024 Nanjing R] 地铁
Priestess_SLG · · 题解
考虑用一个二元组
注意到导致边的数量爆炸的原因主要是换乘,因此考虑优化这个部分。在某个车站从线路
然后注意到
具体来说,跑 dijkstra 的过程中若当前弹出的状态是
:::success[Code]
namespace lowspeed_song {
inline void init() {
}
vector<int> rail[N];
int n, k, a[N], b[N], frt[N], bel[N], e[N], pos[N], idx_, w[N], dis[N], res[N], vis[N];
namespace LiChaoSgt {
vector<int> tree[N];
pair<int, int> seg[N];
inline int calc(int id, int u, int x) {
if (!id) return inf;
return seg[id].first * a[bel[rail[u][x]]] + seg[id].second;
}
inline void ins(int u, int l, int r, int rt, int id) {
if (l == r) {
if (!tree[u][rt] || calc(id, u, l) < calc(tree[u][rt], u, l)) tree[u][rt] = id;
return;
} int mid = l + r >> 1;
if (calc(id, u, mid) < calc(tree[u][rt], u, mid)) swap(tree[u][rt], id);
if (calc(id, u, l) < calc(tree[u][rt], u, l)) ins(u, l, mid, rt << 1, id);
if (calc(id, u, r) < calc(tree[u][rt], u, r)) ins(u, mid + 1, r, rt << 1 | 1, id);
}
inline void ins(int u, int k, int b, int id) { seg[id] = {k, b}, ins(u, 0, (int)rail[u].size() - 1, 1, id); }
inline int qry(int u, int l, int r, int rt, int val) {
if (l == r) return calc(tree[u][rt], u, val);
int mid = l + r >> 1, now = calc(tree[u][rt], u, val);
if (val <= mid) return min(now, qry(u, l, mid, rt << 1, val));
return min(now, qry(u, mid + 1, r, rt << 1 | 1, val));
}
inline int qry(int u, int pos) { return qry(u, 0, (int)rail[u].size() - 1, 1, pos); }
}
inline void sol([[maybe_unused]]int __testcase_id) {
cin >> n >> k;
for (int i = 1; i <= k; ++i) cin >> a[i];
for (int i = 1; i <= k; ++i) cin >> b[i];
for (int i = 1; i <= k; ++i) {
int p, x, las = ++idx_;
cin >> p >> x;
frt[las] = x, bel[las] = i, rail[x].emplace_back(las);
for (int j = 1; j < p; ++j) {
int c, now = ++idx_; cin >> c >> x;
frt[now] = x, bel[now] = i, rail[x].emplace_back(now);
e[las] = now, w[las] = c, las = now;
}
}
for (int i = 1; i <= n; ++i) sort(rail[i].begin(), rail[i].end(), [&](auto &x, auto &y) { return a[bel[x]] < a[bel[y]]; });
for (int i = 1; i <= n; ++i) LiChaoSgt::tree[i].resize(rail[i].size() * 4 + 5);
memset(dis, 0x3f, sizeof dis), memset(res, 0x3f, sizeof res);
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
for (int &i : rail[1]) dis[i] = 0, q.emplace(0, i);
// cerr << "!!!\n";
while (q.size()) {
auto [D, id] = q.top();
q.pop();
if (vis[id] || D != dis[id]) continue;
vis[id] = 1;
int u = frt[id], c = bel[id];
res[u] = min(res[u], D), LiChaoSgt::ins(u, b[c], D, id);
if (e[id] && dis[e[id]] > D + w[id]) dis[e[id]] = D + w[id], q.emplace(dis[e[id]], e[id]);
while (pos[u] < rail[u].size() && vis[rail[u][pos[u]]]) ++pos[u];
if (pos[u] < rail[u].size()) {
int nd = LiChaoSgt::qry(u, pos[u]);
if (dis[rail[u][pos[u]]] > nd) dis[rail[u][pos[u]]] = nd, q.emplace(nd, rail[u][pos[u]]);
}
}
for (int i = 2; i <= n; ++i) cout << res[i] << ' ';
cout << '\n';
}
} // namespace lowspeed_song
:::