日常刷题2025-3-6
日常刷题2025-3-6
P10206 [JOI 2024 Final] 建设工程 2 / Construction Project 2
绿色
思路:最短路+二分
- 第一种情况,S 到 T 的最短路长度已经 ≤K,那么任何一种合法的加边方式都成立。直接输出 N×(N−1) / 2。
- 第二种情况,从 S 到某一点 X,X 再通过边权为 L 的边到达 Y ,Y 最后到达 T。
那么只需先预处理 S 到每个点的最短路,和 T 到每个点的最短路,在判断边权是否小于 K。
但这样枚举 X 和 Y 显然为超时,考虑到排序每个点到 T 的最短路,二分找出最后一个满足条件的数即可。
代码
#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
i64 n, m;
std::cin >> n >> m;
i64 s, t, l, k;
std::cin >> s >> t >> l >> k;
std::vector g(n+1, std::vector<pll>());
for (int i = 0; i < m; i++){
int u, v, w;
std::cin >> u >> v >> w;
g[u].push_back({v, w});
g[v].push_back({u, w});
}
std::vector<i64> dis(n+1);
std::vector<bool> vis(n+1);
auto dij = [&](int st)->void{
for (int i = 1; i <= n; i++) dis[i] = LONG_LONG_MAX;
for (int i = 1; i <= n; i++) vis[i] = 0;
std::priority_queue<pll, std::vector<pll>, std::greater<pll> > q;
q.push({0, st});
dis[st] = 0;
while(!q.empty()){
auto [w, cur] = q.top(); q.pop();
if (vis[cur]) continue;
vis[cur] = 1;
for (auto [to, dd] : g[cur]){
if (dis[to] > dis[cur] + dd){
dis[to] = dis[cur] + dd;
q.push({dis[to], to});
}
}
}
};
dij(t);
if(dis[s]<=k){
std::cout << n*(n-1)/2 << '\n';
return;
}
std::vector<i64> dis2(n+1);
for (int i = 1; i <= n; i++) dis2[i] = dis[i];
std::sort(dis2.begin()+1, dis2.end());
dij(s);
i64 ans = 0;
for (int i = 1; i <= n; i++){
if (dis[i] == LONG_LONG_MAX) continue;
i64 lo = 0, r = n;
while (lo < r){
i64 mid = (lo + r + 1)/2;
if (dis2[mid] <= k - dis[i] - l){
lo = mid;
}else{
r = mid - 1;
}
}
ans += lo;
}
std::cout << ans << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

浙公网安备 33010602011771号