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;
}

双倍经验

posted @ 2022-11-09 20:50  Kobe303  阅读(19)  评论(0编辑  收藏  举报