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

浙公网安备 33010602011771号