【USACO09JAN】安全出行Safe Travel(最短路树+并查集优化)

版权声明:虽然我很菜,不过转载请标明出处。 https://blog.csdn.net/Patrickpwq/article/details/86629729

萌新冒泡

首先有个套路 只要题目中说了源点到每个点最短路径是唯一的 那往往都和最短路树有关系

题意是求不能经过最后一条边的次短路 要使得这条路最短 显然要尽量的多走最短路径上的路 

假设现在要求1->x 我们考虑走了一段最短路径后如何跳到x点

设当前点为u 选择与u点相连的一条非树边(这条边连向x的子树内的某点v) 然后ans[x]=dis[u]+w(u,v)+(dis[v]-dis[x])

然后我们就可以暴力枚举每条非树边暴力更新啦!

仔细观察发现 对于每条非树边 dis[u]+w(u,v)+dis[v]是个定值

wow 那把这个值算出来 排个序 似乎还是要扫一遍?不过如果强烈安利并查集——可以维护哪些点已经被修改过了,因为被修改过的点肯定是连续的

然后好像卡SPFA是出题人的基本素养

#include<bits/stdc++.h>
const int N=100005;
const int M=200005;
const int INF=0x3f3f3f3f;
using namespace std;
int n,m;
struct Edge
{
	int from,to,next,val;
}edge[2*M];
int first[N],tot;
inline void addedge(int x,int y,int z)
{
	tot++;
	edge[tot].from=x; edge[tot].to=y; edge[tot].next=first[x]; edge[tot].val=z; first[x]=tot;
}
typedef pair<int,int> Pair;
priority_queue<Pair,vector<Pair>,greater<Pair> > heap;
int dis[N],father[N];
bool done[N];
void Dijkstra()
{
	memset(dis,0x3f,sizeof(dis));
	memset(done,0,sizeof(done));
	dis[1]=0; heap.push(make_pair(0,1)); father[1]=0;
	while(!heap.empty())
	{
		int now=heap.top().second;
		heap.pop();
		if(done[now])	continue;
		done[now]=1;
		for(int u=first[now];u;u=edge[u].next)
		{
			int vis=edge[u].to;
			if(dis[now]+edge[u].val<dis[vis])
			{
				dis[vis]=dis[now]+edge[u].val;
				father[vis]=now;
				heap.push(make_pair(dis[vis],vis));
			}
		}
	}
}
struct Tree
{
	int val,from,to;
	bool operator <(const Tree &p) const
	{
		return this->val<p.val;
	}
}tree[M];
int fa[N],ans[N];
inline int getfather(int x)
{
	if(fa[x]==x)	return x;
	fa[x]=getfather(fa[x]);
	return fa[x];
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cin>>n>>m;
	for(int i=1,x,y,z;i<=m;i++)
	{
		cin>>x>>y>>z;
		addedge(x,y,z); addedge(y,x,z);
	}
	Dijkstra();
//	for(int i=1;i<=n;i++)	cout<<father[i]<<endl;

	int cnt=0;
	for(int i=1,x,y;i<=tot;i+=2)
	{
		x=edge[i].from; y=edge[i].to;
		if(father[x]==y||father[y]==x)	continue;
		//非树边 
		tree[++cnt].val=dis[x]+dis[y]+edge[i].val;
		tree[cnt].from=x; 
		tree[cnt].to=y;
	}
	sort(tree+1,tree+cnt+1);
	for(int i=1;i<=n;i++)	fa[i]=i;
	memset(ans,-1,sizeof(ans));
	for(int i=1,x,y;i<=cnt;i++)
	{
		x=getfather(tree[i].from); y=getfather(tree[i].to);
		while(x!=y)
		{
			if(dis[x]<dis[y]) swap(x,y);	//默认x更深 
			ans[x]=tree[i].val-dis[x];
			fa[x]=father[x];
			x=getfather(x);
		}
	}
	for(int i=2;i<=n;i++)	cout<<ans[i]<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Patrickpwq/article/details/86629729