P10206 [JOI 2024 Final] 建设工程 2 / Construction Project 2 题解

题目传送门

思路

简单题。分别从 \(s\)\(t\) 跑 dijkstra 求最短路。记 \(dist(i,j)\) 代表 \(i \to j\) 的最短路长度。当 \(dist(s,t) \le k\) 时,答案为 \(\displaystyle \frac{n \times (n-1)}{2}\)。否则,我们枚举每一个点 \(u\),最后二分求得到满足 \(dist(s,u) + dist(t, v) + L \le k\)\(v\) 的数量,求和即为答案。时间复杂度 \(\mathcal{O}(n \log n)\)

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> pr;

const int N = 2e5 + 5;

struct Edge
{
	int v, w;
};

int n, m, s, t, l, k;
int dist[2][N], tmp[N], cnt[N];
bool vis[N];
vector<Edge> tr[N];
unordered_map<int, int> mp;

void dijkstra(int x, int op)
{
	memset(dist[op], 0x3f, sizeof(dist[op]));
	memset(vis, 0, sizeof(vis));
	priority_queue<pr, vector<pr>, greater<pr> > q;
	dist[op][x] = 0;
	q.push({0, x});
	while (q.size())
	{
		int u = q.top().second;
		q.pop();
		if (vis[u]) continue;
		vis[u] = 1;
		for (Edge v : tr[u])
		{
			if (!vis[v.v] && dist[op][v.v] > dist[op][u] + v.w)
			{
				dist[op][v.v] = dist[op][u] + v.w;
				q.push({dist[op][v.v], v.v});
			}
		}
	}
}

signed main()
{
	scanf("%lld%lld%lld%lld%lld%lld", &n, &m, &s, &t, &l, &k);
	for (int i = 1, u, v, w; i <= m; i++)
	{
		scanf("%lld%lld%lld", &u, &v, &w);
		tr[u].push_back({v, w});
		tr[v].push_back({u, w});
	}
	dijkstra(s, 0);
	dijkstra(t, 1);
	for (int i = 1; i <= n; i++)
		tmp[i] = dist[1][i];
	sort(tmp + 1, tmp + n + 1);
	int len = unique(tmp + 1, tmp + n + 1) - tmp - 1;
	for (int i = 1; i <= len; i++)
		mp[tmp[i]] = i;
	for (int i = 1; i <= n; i++)
		cnt[mp[dist[1][i]]]++;
	for (int i = 1; i <= len; i++)
		cnt[i] += cnt[i - 1];
	int ans = 0;
	if (dist[0][t] <= k) ans = n * (n - 1) / 2;
	else
	{
		for (int i = 1; i <= n; i++)
		{
			int val = k - l - dist[0][i];
			if (val < 0) continue;
			int pos = upper_bound(tmp + 1, tmp + len + 1, val) - tmp - 1;
			ans += cnt[pos];
		}
	}
	printf("%lld\n", ans);
	return 0;
}
posted @ 2025-10-19 10:56  lucasincyber  阅读(2)  评论(0)    收藏  举报