分析:
先用Heap_Dijkstra()求一遍u到所有点的单源最短路。
然后对于有向边i如果有dis[begin[i]]+length[i]==dis[end[i]],那么这条有向边i就是最短路上的边。
将所有这样的边找出来跑朱刘算法求一遍最小树形图即可。
因为只包含最短路边的图肯定是一张DAG,所以求最小树形图的算法会好写很多。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
typedef long long LL;
inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}
const int MAXN=3e5+5;
const int MAXM=3e5+5;
int n,m,s,ecnt,head[MAXN];
LL dis[MAXN],len[MAXN],ans;
bool vis[MAXN];
struct Edge{
int to,nxt;
LL w;
}e[MAXM<<1];
struct Pair{
int pos;
LL dis;
friend bool operator > (Pair x,Pair y){
return x.dis>y.dis;
}
};
std::priority_queue<Pair,std::vector<Pair>,std::greater<Pair> > q;
inline void add_edge(int bg,int ed,int val){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
e[ecnt].w=val;
head[bg]=ecnt;
}
inline void dijkstra(){
memset(dis,0x3f,sizeof dis);
while(!q.empty()) q.pop();
dis[s]=1;
q.push((Pair){s,0});
while(!q.empty()){
int u=q.top().pos;q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int ver=e[i].to;
if(dis[ver]>dis[u]+e[i].w){
dis[ver]=dis[u]+e[i].w;
q.push((Pair){ver,dis[ver]});
}
}
}
}
inline void zhuliu(){
memset(len,0x3f,sizeof len);
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=e[j].nxt){
int ver=e[j].to;
if(dis[ver]==dis[i]+e[j].w)
len[ver]=std::min(len[ver],e[j].w);
}
for(int i=1;i<=n;i++)
if(i!=s) ans+=len[i];
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read(),w=read();
add_edge(u,v,w);
add_edge(v,u,w);
}
s=read();
dijkstra();
zhuliu();
printf("%lld\n",ans);
return 0;
}