ABC250Ex
令 disi 表示 i 到离它最近的充电站的距离。
这个很好办,建立一个超级源点,连向所有充电站,边权为 0,跑一遍最短路即可。
设走到点 u,剩余电量为 x,所需的最小容量是 c,则有
disu≤x≤c−disu
因为 u 点剩余的电量一定可以到离它最近的充电站完成一次充电,而且电量最多也只会是从离它最近的加油站加满油之后来到 u。
通过边 (u,v,w) 之后,v 也满足上述条件,即
disv≤x−w≤c−disv
将上述两个式子合并一下可以得到
disv≤c−disu−w
移项可得
c≥disu+disv+w
于是给出了对最小容量的限制。
于是将原图中的边 (u,v,w) 的边权都变成 disu+disv+w,建出最小生成树,然后倍增求路径上的最大值即可。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, int> pli;
const int N = 200005, M = 200005;
int n, t, m, k, Q;
int head[N], ver[M*2+N*2], nxt[M*2+N*2], cnt; ll wei[M*2+N*2];
ll dis[N]; bool vis[N];
struct node {
int u, v; ll w;
} E[M];
int fa[N];
int F[N][19], dep[N]; ll mx[N][19];
void add(int u, int v, ll w) {
ver[++cnt] = v, wei[cnt] = w, nxt[cnt] = head[u], head[u] = cnt;
}
void dij() {
priority_queue<pli> q;
q.push(pli(0, 0));
memset(dis, 0x3f, sizeof dis); dis[0] = 0;
while (!q.empty()) {
int u = q.top().second; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = head[u]; i; i = nxt[i]) {
int v = ver[i], w = wei[i];
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
q.push(pli(-dis[v], v));
}
}
}
}
int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
void kruskal() {
memset(head, 0, sizeof head); cnt = 0;
for (int i = 1; i <= n; ++i) fa[i] = i;
sort(E + 1, E + m + 1, [](node a, node b) {
return a.w < b.w;
});
for (int i = 1; i <= m; ++i) {
int u = E[i].u, v = E[i].v; ll w = E[i].w;
int fu = find(u), fv = find(v);
if (fu == fv) continue;
fa[fu] = fv, add(u, v, w), add(v, u, w);
}
}
void dfs(int u, int fa) {
for (int i = head[u]; i; i = nxt[i]) {
int v = ver[i]; ll w = wei[i];
if (v == fa) continue;
F[v][0] = u, mx[v][0] = w, dep[v] = dep[u] + 1;
for (int j = 1; j <= t; ++j)
F[v][j] = F[F[v][j - 1]][j - 1], mx[v][j] = max(mx[v][j - 1], mx[F[v][j - 1]][j - 1]);
dfs(v, u);
}
}
ll LCA(int x, int y) {
ll res = 0;
if (dep[x] < dep[y]) swap(x, y);
for (int i = t; ~i; --i)
if (dep[y] <= dep[F[x][i]]) res = max(res, mx[x][i]), x = F[x][i];
if (x == y) return res;
for (int i = t; ~i; --i)
if (F[x][i] != F[y][i]) res = max(res, max(mx[x][i], mx[y][i])), x = F[x][i], y = F[y][i];
return max(res, max(mx[x][0], mx[y][0]));
}
int main() {
scanf("%d%d%d", &n, &m, &k); t = (log(n) / log(2)) + 1;
for (int i = 1; i <= m; ++i) {
int u, v; ll w; scanf("%d%d%lld", &u, &v, &w);
add(u, v, w), add(v, u, w);
E[i].u = u, E[i].v = v, E[i].w = w;
}
for (int i = 1; i <= k; ++i) add(0, i, 0), add(i, 0, 0);
dij();
for (int i = 1; i <= m; ++i) E[i].w += dis[E[i].u] + dis[E[i].v];
kruskal();
dfs(1, 0);
scanf("%d", &Q);
while (Q--) {
int x, y; ll t; scanf("%d%d%lld", &x, &y, &t);
if (LCA(x, y) <= t) printf("Yes\n");
else printf("No\n");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】