专栏文章
题解:P10206 [JOI 2024 Final] 建设工程 2 / Construction Project 2
P10206题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mio4n2m7
- 此快照首次捕获于
- 2025/12/02 13:17 3 个月前
- 此快照最后确认于
- 2025/12/02 13:17 3 个月前
题意
给定一个无向图,可以在任意两点间建一条长度为 的边,求建边后 到 的最短路长度 的方案数。
思路
观察如下图示(有点丑)。

不妨设点 到点 的最短路长度为 ,点 到点 的最短路长度为 。在如上情况中,添加一条连接 与 的长度为 的边后,(即 到 的最短路长度)为 我们的目的就转换为求 的个数。
进一步转换,将原式移项得:。
跑两次最短路可分别求出 和 每一项的值,最终答案可使用二分求解。
代码
CPP#include<bits/stdc++.h>
#define int long long
#define double long double
#define fi first
#define se second
using namespace std;
const int N=2e5+10;
int n,m;
int s,t,l,k;
struct node{
int v,w;
};
vector<node>g[N];
int dis1[N],dis2[N];
bool vis1[N],vis2[N];
struct node2{
int u,dis;
bool operator>(const node2 &a)const{
return dis>a.dis;
}
};
priority_queue<node2,vector<node2>,greater<node2> >pq1,pq2;
void dij1(){//求dis1
memset(dis1,0x3f,sizeof dis1);
dis1[s]=0;
pq1.push({s,0});
while(pq1.size()){
int u=pq1.top().u;
pq1.pop();
if(vis1[u]){
continue;
}
vis1[u]=1;
for(auto i:g[u]){
int v=i.v,w=i.w;
if(dis1[v]>dis1[u]+w){
dis1[v]=dis1[u]+w;
pq1.push({v,dis1[v]});
}
}
}
return ;
}
void dij2(){//求dis2
memset(dis2,0x3f,sizeof dis2);
dis2[t]=0;
pq2.push({t,0});
while(pq2.size()){
int u=pq2.top().u;
pq2.pop();
if(vis2[u]){
continue;
}
vis2[u]=1;
for(auto i:g[u]){
int v=i.v,w=i.w;
if(dis2[v]>dis2[u]+w){
dis2[v]=dis2[u]+w;
pq2.push({v,dis2[v]});
}
}
}
return ;
}
signed main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
cin>>s>>t>>l>>k;
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
g[a].push_back({b,c});
g[b].push_back({a,c});
}
dij1();
dij2();
if(dis1[t]<=k){
cout<<n*(n-1)/2<<endl;
return 0;
}
sort(dis1+1,dis1+1+n);
int ans=0;
for(int v=1;v<=n;v++){
int tmp=k-l-dis2[v];//转换后的式子
int lb=upper_bound(dis1+1,dis1+1+n,tmp)-dis1-1;//二分求答案
ans+=lb;
}
cout<<ans<<endl;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...