随机到了一个神秘题目。
题目大意
在 $n$ 个点的无向图中,有 $k$ 个点有守卫。假如你携带有 $x$ 千克的铀,那么你在移动时与这些守卫的距离必须都大于 $x$。
多组询问,回答从点 $x$ 运输到点 $y$ 最多能运输多少铀。
分析
这题对算法的考察较为综合,卡了我一天。
首先需要求出每个点到最近的守卫的距离 $dis$,在 dijkstra 时设置多个起点即可。
把每个边的权值设置为两个端点 $dis$ 的最小值,重新建图 $G_2$。
接下来是关键的一步:得到 $G_2$ 的最大生成树 $G_3$,任何运输路径都在最大生成树上。
最后用 LCA 维护树两点之间路径的权值 $\min$。
int main() {
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++) {
int x, y, z;
cin >> x >> y >> z;
G1[x].push_back({y, z});
G1[y].push_back({x, z});
}
int k;
cin >> k;
vector<int> start(k);
for (auto &si : start)
cin >> si;
auto dis = dijkstra(n, start);
for (int u = 1; u <= n; u++) {
for (auto [v, w] : G1[u]) {
ll tw = min(dis[u], dis[v]);
G2[u].push_back({v, max<ll>(0, tw - 1)});
}
}
kruskal(n);
int Q;
cin >> Q;
LCA<N> lca(n + 1, 1);
while (Q--) {
int x, y;
cin >> x >> y;
cout << lca.query(x, y) << "\n";
}
return 0;
}
全部代码请看:Luogu/8x/P8240.cpp。