bzoj 1576: [Usaco2009 Jan]安全路经Travel——并查集+dijkstra
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
—————————————————————————————————
由于最短路唯一,先求最短路径树,考虑非树边uv,它能使uv以上,lca以下的点多一种路径,长度为dis[u] + dis[v] + edge[i] - dis[x]。
因为dis[x]是常数 我们令这条非树边的值为val[i] = dis[u] + dis[v] + edge[i],我们只需对每个x,找出最小的val。
可以先按val排序,然后使用并查集压缩路径即可。
因为已经赋值过的点一定比现在解更优 所以防止多次算到一个点 我们可以把他们合并起来一起跳过
这道题不能写spfa会被卡QAQ dj快很多 spfa佳slf优化也很慢 勉强能过
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int N=1e5+7,M=4e5+7,inf=0x3f3f3f3f; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,ans[N]; int f[N],fa[N]; int find(int x){while(x!=f[x]) x=f[x]=f[f[x]]; return x;} int first[N],cnt,cntq; struct node{int from,to,next,w;}e[M],qs[M]; bool cmp(node a,node b){return a.w<b.w;} void ins(int a,int b,int w){e[++cnt]=(node){a,b,first[a],w}; first[a]=cnt;} void insert(int a,int b,int w){ins(a,b,w); ins(b,a,w);} int dis[N],dep[N]; struct Q{ int d,pos; bool operator <(const Q& x)const{return x.d<d;} }; priority_queue<Q>q; void dj(){ memset(dis,0x3f,sizeof(dis)); q.push((Q){0,1}); dis[1]=0; while(!q.empty()){ Q p=q.top(); q.pop(); if(p.d>dis[p.pos]) continue; int x=p.pos; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(dis[now]>dis[x]+e[i].w){ dis[now]=dis[x]+e[i].w; dep[now]=dep[x]+1; fa[now]=x; q.push((Q){dis[now],now}); } } } } int main(){ int x,y,w; n=read(); m=read(); for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=m;i++) x=read(),y=read(),w=read(),insert(x,y,w); dj(); for(int i=1;i<=cnt;i++){ x=e[i].from; y=e[i].to; if(dep[x]<dep[y]) swap(x,y); if(dis[x]==dis[y]+e[i].w) continue; qs[++cntq]=(node){x,y,0,dis[x]+dis[y]+e[i].w}; } sort(qs+1,qs+1+cntq,cmp); for(int i=1;i<=cntq;i++){ x=qs[i].from; y=qs[i].to; while(x!=y){ if(dep[x]<dep[y]) swap(x,y); if(!ans[x]) ans[x]=qs[i].w-dis[x]; x=f[x]=find(fa[x]); //printf("[%d]\n",x); } } for(int i=2;i<=n;i++){ if(!ans[i]) printf("-1\n"); else printf("%d\n",ans[i]); } return 0; }