【BZOJ-1576】安全路径Travel Dijkstra + 并查集

1576: [Usaco2009 Jan]安全路经Travel

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1044  Solved: 363
[Submit][Status][Discuss]

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

输出解释:

跟题中例子相同

HINT

Source

Gold

Solution

比较简单的一道题

首先我们跑一遍最短路,得到最短路树,在松弛操作的时候加一句话即可

然后我们发现对于不在最短路树上的边,如果把它加入树中,会形成一个环,它会影响这个环上除lca的其他点

样例是这样的,黑边是指最短路树上的边,加入非树红边,影响的是红点,加入非树蓝边,有影响的是蓝点

所发生的影响就是,环上点x,在加入边<u,v>会被更新成dis[u]+dis[v]+val<u,v>-dis[x]

所以要求被更新后最小,就是要求dis[u]+dis[v]+val<u,v>最小,那么我们按照这个价值对非树边排序

从权值小的开始更新。

所以这样的话,中间会更新一些重复的,我们只要保证那些重复的不被更新即可,这个显然可以利用并查集维护一下

这样时间复杂度大概是$O(nlogn+n×a(n))$

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
#define MAXN 100010
#define MAXM 200010
int N,M;
struct EdgeNode{int next,to,t,from;}edge[MAXM<<1];
int head[MAXN],cnt=1;
void AddEdge(int u,int v,int w) {cnt++; edge[cnt].from=u; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].t=w;}
void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);}
#define Pa pair<int,int>
#define INF 0x7fffffff
priority_queue<Pa,vector<Pa>,greater<Pa> >q;
int dis[MAXN],fa[MAXN];
void Dijkstra(int S)
{
    for (int i=1; i<=N; i++) dis[i]=INF;
    q.push(make_pair(0,S)); dis[S]=0;
    while (!q.empty())
        {
            int now=q.top().second;
            int Dis=q.top().first;
            q.pop();
            if (Dis>dis[now]) continue;
            for (int i=head[now]; i; i=edge[i].next)
                if (Dis + edge[i].t < dis[edge[i].to])
                    dis[edge[i].to]=Dis+edge[i].t,
                    fa[edge[i].to]=now,
                    q.push(make_pair(dis[edge[i].to],edge[i].to));
        }
}
int f[MAXN];
int F(int x) {if (!f[x]) return x; else return f[x]=F(f[x]);}
struct RoadNode
{    
    int u,v,t;
    bool operator < (const RoadNode & A) const
        {return t<A.t;}
}road[MAXM];
int tot,num;
int ans[MAXN];
void Add(RoadNode x)
{
    int u=x.u,v=x.v,t=x.t;
    while (F(u)!=F(v))
        {
            num++;
            if (dis[F(u)]<dis[F(v)]) swap(u,v);
            ans[F(u)]=min(ans[F(u)],t-dis[F(u)]);
            u=f[F(u)]=fa[F(u)];
        }
}
int main()
{
    N=read(),M=read();
    for (int x,y,z,i=1; i<=M; i++) x=read(),y=read(),z=read(),InsertEdge(x,y,z);
    Dijkstra(1);
    for (int i=2; i<=cnt; i+=2)
        {
            int u=edge[i].from,v=edge[i].to;
            if (fa[u]!=v && fa[v]!=u)
                road[++tot].u=u,road[tot].v=v,road[tot].t=dis[u]+dis[v]+edge[i].t;
        }
    sort(road+1,road+tot+1);
//    for (int i=1; i<=tot; i++)
//        printf("%d %d %d
",road[i].u,road[i].v,road[i].t);
//    for (int i=1; i<=N; i++) printf("%d  ",dis[i]); puts("");
    for (int i=1; i<=N; i++) ans[i]=INF;
    for (int i=1; i<=tot && num<N-1; i++) Add(road[i]);
    for (int i=2; i<=N; i++) printf("%d
",ans[i]==INF? -1:ans[i]);
    return 0;
}

写完就A了....

原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5803248.html