【BZOJ1576】[Usaco2009 Jan]安全路经Travel 最短路+并查集

【BZOJ1576】[Usaco2009 Jan]安全路经Travel

Description

Input

* 第一行: 两个空格分开的数, N和M

* 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i

Output

* 第1..N-1行: 第i行包含一个数:从牛棚_1到牛棚_i+1并且避免从牛棚1到牛棚i+1最短路经上最后一条牛路的最少的时间.如果这样的路经不存在,输出-1.

Sample Input

4 5
1 2 2
1 3 2
3 4 4
3 2 1
2 4 3
输入解释:
跟题中例子相同

Sample Output

3
3
6
输出解释:
跟题中例子相同

题解: 先求出最短路径树,然后我们统计每条非树边对每个点的影响。一条非树边可以更新它覆盖的所有点,如果这条边(x,y,len)覆盖了z,那么ans[z]=min(ans[z],dis[x]+dis[y]+len-dis[z]),因为dis[z]是确定的,所以我们维护链上的dis[x]+dis[y]+len的最小值即可。

如何维护?树剖+线段树,倍增,都是不错的方案,当然有更巧的。将所有非树边按dis[x]+dis[y]+len从小到大排序,然后用并查集维护所有没被更新的点,暴力更新路径上没被更新的点即可。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <utility>
#define mp(A,B) make_pair(A,B)
using namespace std;
const int maxn=100010;
int n,m,cnt;
int to[maxn<<2],next[maxn<<2],val[maxn<<2],head[maxn],dis[maxn],fa[maxn],pre[maxn];
int f[maxn],s[maxn],ans[maxn];
bool vis[maxn];
priority_queue<pair<int,int> > q;
struct edge
{
	int a,b,v;
	bool ont;
}p[maxn<<1];
inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd()
{
	int ret=0,f=1;	char gc=nc();
	while(!isdigit(gc))	{if(gc=='-')	f=-f;	gc=nc();}
	while(isdigit(gc))	ret=ret*10+gc-'0',gc=nc();
	return ret*f;
}
inline void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
bool cmp(const edge &a,const edge &b)
{
	return a.v<b.v;
}
int find(int x)
{
	return (f[x]==x)?x:(f[x]=find(f[x]));
}
int main()
{
	n=rd(),m=rd();
	memset(head,-1,sizeof(head));
	register int i,u,a,b;
	for(i=1;i<=m;i++)	p[i].a=rd(),p[i].b=rd(),p[i].v=rd(),add(p[i].a,p[i].b,p[i].v),add(p[i].b,p[i].a,p[i].v);
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0,q.push(mp(0,1));
	while(!q.empty())
	{
		u=q.top().second,q.pop();
		if(vis[u])	continue;
		vis[u]=1;
		for(i=head[u];i!=-1;i=next[i])	if(dis[to[i]]>dis[u]+val[i])
			fa[to[i]]=u,pre[to[i]]=(i>>1)+1,dis[to[i]]=dis[u]+val[i],q.push(mp(-dis[to[i]],to[i]));
	}
	for(i=1;i<=n;i++)	f[i]=i,p[pre[i]].ont=1;
	for(i=1;i<=m;i++)	p[i].v+=dis[p[i].a]+dis[p[i].b];
	sort(p+1,p+m+1,cmp);
	for(i=1;i<=m;i++)	if(!p[i].ont)
	{
		a=find(p[i].a),b=find(p[i].b);
		while(a!=b)
		{
			if(dis[a]<dis[b])	swap(a,b);
			ans[a]=p[i].v-dis[a],f[a]=fa[a],a=find(f[a]);
		}
	}
	for(i=2;i<=n;i++)	printf("%d\n",(!ans[i])?-1:ans[i]);
	return 0;
}

 

posted @ 2017-10-15 14:50  CQzhangyu  阅读(277)  评论(0编辑  收藏  举报