【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
输入解释:
跟题中例子相同
1 2 2
1 3 2
3 4 4
3 2 1
2 4 3
输入解释:
跟题中例子相同
Sample Output
3
3
6
输出解释:
跟题中例子相同
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; }
| 欢迎来原网站坐坐! >原文链接<