ABC250Ex
令 \(dis_i\) 表示 \(i\) 到离它最近的充电站的距离。
这个很好办,建立一个超级源点,连向所有充电站,边权为 \(0\),跑一遍最短路即可。
设走到点 \(u\),剩余电量为 \(x\),所需的最小容量是 \(c\),则有
\[dis_u\le x\le c-dis_u
\]
因为 \(u\) 点剩余的电量一定可以到离它最近的充电站完成一次充电,而且电量最多也只会是从离它最近的加油站加满油之后来到 \(u\)。
通过边 \((u,v,w)\) 之后,\(v\) 也满足上述条件,即
\[dis_v\le x-w\le c-dis_v
\]
将上述两个式子合并一下可以得到
\[dis_v\le c-dis_u-w
\]
移项可得
\[c\ge dis_u+dis_v+w
\]
于是给出了对最小容量的限制。
于是将原图中的边 \((u,v,w)\) 的边权都变成 \(dis_u+dis_v+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;
}