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

Sample Output

3
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;
}
View Code

 

posted @ 2017-08-27 19:55  友人Aqwq  阅读(192)  评论(0编辑  收藏  举报