51Nod 1443 路径和树

还是一道很简单的基础题,就是一个最短路径树的类型题目

我们首先可以发现这棵树必定满足从1出发到其它点的距离都是原图中的最短路

换句话说,这棵树上的每一条边都是原图从1出发到其它点的最短路上的边

那么直接跑最短路,SPFA,不存在的?我只信DJ,然后记录那些边在最短路上

然后直接跑MST即可。是不是很经典的水题

然后我又莫名拿了Rank1(没办法天生自带小常数

CODE

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int N=3e5+5;
struct edge
{
	int from,to,next,v;
}e[N<<1];
struct heap
{
	int num; LL s;
	bool operator < (const heap a) const { return a.s<s; }
};
struct data
{
	int l,r,s;
}a[N];
priority_queue <heap> small;
int head[N],cnt,father[N],n,m,x,y,z,s,tot;
LL dis[N];
bool vis[N];
inline char tc(void)
{
	static char fl[100000],*A=fl,*B=fl;
	return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
	x=0; char ch; while (!isdigit(ch=tc()));
	while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void double_add(int x,int y,int z)
{
	e[++cnt].from=x; e[cnt].to=y; e[cnt].next=head[x]; e[cnt].v=z; head[x]=cnt;
	e[++cnt].from=y; e[cnt].to=x; e[cnt].next=head[y]; e[cnt].v=z; head[y]=cnt;
}
inline bool cmp(data a,data b)
{
	return a.s<b.s;
}
inline int getfather(int k)
{
	return father[k]^k?father[k]=getfather(father[k]):k;
}
inline LL MST(void)
{
	register int i; LL ans=0;
	sort(a+1,a+tot+1,cmp);
	for (i=1;i<=n;++i)
	father[i]=i;
	for (i=1;i<=tot;++i)
	{
		int fx=getfather(a[i].l),fy=getfather(a[i].r);
		if (!vis[a[i].r]&&fx!=fy) father[fx]=fy,ans+=a[i].s,vis[a[i].r]=1;
	}
	return ans;
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	int i; read(n); read(m);
	memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e));
	for (i=1;i<=m;++i)
	read(x),read(y),read(z),double_add(x,y,z);
	memset(dis,63,sizeof(dis)); read(s); 
	dis[s]=0; small.push((heap){s,0});
	while (!small.empty())
	{
		int now=small.top().num; small.pop();
		if (vis[now]) continue; vis[now]=1;
		for (i=head[now];i!=-1;i=e[i].next)
		if (dis[e[i].to]>dis[now]+1LL*e[i].v)
		{
			dis[e[i].to]=dis[now]+1LL*e[i].v;
			small.push((heap){e[i].to,dis[e[i].to]});
		}
	}
	memset(vis,0,sizeof(vis));
	for (i=1;i<=cnt;++i)
	if (dis[e[i].from]+1LL*e[i].v==dis[e[i].to]) a[++tot]=(data){e[i].from,e[i].to,e[i].v};
	return printf("%lld",MST()),0;
}
原文地址:https://www.cnblogs.com/cjjsb/p/9339187.html