题解 CF545E 【Paths and Trees】
思路:
\(\quad\)只需要以题目给定的 \(u\) 为起点跑一遍 \(Dijkstra\) 最短路即可,每次记录每个点的前驱(即到达这个点的边),注意有多个可以选择的边中选择边权最小的,感觉很像一个最小生成树,最后记得要记录树上的边权并排序再输出,起点 \(u\) 是没有前驱的,所以要从 \(2\) 开始输出。
\(\quad\)如果还不能理解就看看代码吧,有一些关键的注释。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
#define re register int
#define int long long
#define LL long long
#define il inline
#define next nee
#define inf 1e18
il int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
il void print(int x)
{
if(x<0)putchar('-'),x=-x;
if(x/10)print(x/10);
putchar(x%10+'0');
}
const int N=3e5+5;
int n,m,next[N<<1],go[N<<1],head[N],tot,dis[N],s[N<<1],t,du[N],ans;
bool b[N];
il void Add(int x,int y,int z)
{
next[++tot]=head[x];head[x]=tot;
go[tot]=y;s[tot]=z;
}
struct node{
int pos,dis;
il bool operator<(const node &x)const
{return dis>x.dis;}
};
priority_queue<node>q;
il void Dijkstra(int p)//板子Dijkstra
{
for(re i=1;i<=n;i++)dis[i]=inf;dis[p]=0;
q.push((node){p,0});
while(!q.empty())
{
node tmp=q.top();q.pop();
int x=tmp.pos;
if(b[x])continue;
b[x]=1;
for(re i=head[x];i;i=next[i])
{
int y=go[i];
if(dis[y]>dis[x]+s[i])
{
du[y]=i;//du记录前驱编号为i的边
dis[y]=dis[x]+s[i];
q.push((node){y,dis[y]});
}
else if(dis[y]==dis[x]+s[i])//有多条最短路径时
{if(s[du[y]]>s[i])du[y]=i;}//选择边权小的
}
}
}
signed main()
{
n=read();m=read();
for(re i=1;i<=m;i++)
{re x=read(),y=read(),z=read();Add(x,y,z);Add(y,x,z);}
t=read();
Dijkstra(t);
for(re i=1;i<=n;i++)ans+=s[du[i]];//ans统计答案
for(re i=1;i<=n;i++)dis[i]=du[i]+1>>1;
sort(dis+1,dis+n+1);//别忘了排序
print(ans);putchar('\n');
for(re i=2;i<=n;i++)print(dis[i]),putchar(' ');//从2开始输出
return 0;
}