[USACO09JAN]安全出行Safe Travel(最短路径树)

传送门

求对于每个点删掉1到他的最短路上的最后一条边(就是这条路径上与他自己相连的那条边)后1到他的最短路的长度。

即:最短路径树:图中的源点到所有结点的最短路径构成的树。

最短路径树在dijkstra过程中就可以求出来,因为这个过程就相当于走一棵树。

然后就是选入杂边,对于一条杂边<u,v>,它加入后会形成一个环,这个环上所有的点除了lca都可以被这条杂边更新,即这些点删去它上面那条边后是可以走杂边的,但lca删去上面那条边后图就不连通了。

那么

disnew[x]=dis[u]+dis[v]+w[i]−dis[x]

对于一条杂边,前面那三个量是一定的。 每一个点,我们希望用最小的杂边更新他,更新过后就不再更新。 于是可以按w排序杂边,依次更新,更新过后的点就用并查集缩起来,以保证每个点只被更新一次。

//要题目中说了源点到每个点最短路径是唯一的 那往往都和最短路树有关系
#include<bits/stdc++.h>
#define N 100003
#define M 200003
#define INF 2100000000
using namespace std;
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x*f;
}
int tot=1,n;
int head[N],dis[N],ans[N],dep[N],fa[N],pre[N],anc[N],ontree[M*2];
struct EDGE{
    int nextt,to,val;
}w[M*2];
struct Edge{
    int u,v,val;
}za[M*2];
struct qnode{
    int v,c;
    qnode(int _v=0,int _c=0):v(_v),c(_c){}
    bool operator <(const qnode &r)const
    {
        return r.c<c;
    }
};
bool cmp(const Edge &a,const Edge &b)
{
    return a.val<b.val;
}
void add(int a,int b,int c)
{
    tot++;
    w[tot].nextt=head[a];
    w[tot].to=b;
    w[tot].val=c;
    head[a]=tot;
}
int get(int x)
{
    if(fa[x]==x)return x;
    return fa[x]=get(fa[x]);
}
void dij()
{
    priority_queue<qnode>q;
    for(int i=1;i<=n;++i)dis[i]=INF;
    dis[1]=0;
    q.push(qnode(1,0));
    while(!q.empty())
    {
        qnode e=q.top();q.pop();
        int u=e.v;
        for(int i=head[u];i;i=w[i].nextt)
        {
            int v=w[i].to;
            if(dis[v]>dis[u]+w[i].val)
            {
                dis[v]=dis[u]+w[i].val;
                pre[v]=i;anc[v]=u;dep[v]=dep[u]+1;
                q.push(qnode(v,dis[v]));
            }
        }
    }
}
int main()
{
      n=read();int m=read();
      for(int i=1;i<=m;++i)
      {
          int a=read(),b=read(),c=read();
          add(a,b,c);add(b,a,c);
    }
    dij();

    for(int i=2;i<=n;++i)ontree[pre[i]]=1;
    for(int i=1;i<=n;++i)fa[i]=i,ans[i]=INF;
    int cnt=0;
    for(int i=2;i<=tot;++i)
      if(!ontree[i]&&!ontree[i^1])
      {
          za[++cnt].u=w[i].to;
          za[cnt].v=w[i^1].to;
          za[cnt].val=dis[w[i].to]+dis[w[i^1].to]+w[i].val;
      }
    sort(za+1,za+1+cnt,cmp);
    for(int i=1;i<=cnt;++i)
    {
        int u=za[i].u,v=za[i].v;
        u=get(u);v=get(v);
        while(u!=v)
        {
            if(dep[u]<dep[v])swap(u,v);//从下往上并上去
            ans[u]=min(ans[u],za[i].val-dis[u]);
            u=fa[u]=get(anc[u]);
        }
    }
    for(int i=2;i<=n;++i)
    {
        if(ans[i]<INF)printf("%d\n",ans[i]);
        else printf("-1\n");
    }
} 

原文地址:https://www.cnblogs.com/yyys-/p/11387343.html

时间: 2024-11-10 08:24:37

[USACO09JAN]安全出行Safe Travel(最短路径树)的相关文章

[USACO09JAN]安全出行Safe Travel

[USACO09JAN]安全出行Safe Travel 题目描述 Gremlins have infested the farm. These nasty, ugly fairy-like creatures thwart the cows as each one walks from the barn (conveniently located at pasture_1) to the other fields, with cow_i traveling to from pasture_1 t

[usaco jan 09] 安全路径 travel [最短路径树]

题面: 传送门 思路: 既然最后一条边不能走,那么就一定是换了一条路,一条不经过这最后一条边的路 如果想要这条路最短,那么其在路上一定尽可能多地走了最短路径 因此,我们对这张图跑一遍从1开始的单源最短路,并建立出最短路径树 那么新的路径(1->u)一定是这样构成的:(1->v)+edge(v,w)+(w->u),其中w是u在最短路径树上的后代 那么,我们对于每一条非树边(u,v),其树上路径上所有点(除了lca)的答案,都可以被dis[u]+dis[v]+w(u,v)-dis[路径上的点

WOJ#2423 安全出行Safe Travel

描述 精灵最近在农场上泛滥,它们经常会阻止牛们从农庄(牛棚_1)走到别的牛棚(牛_i的目的 地是牛棚_i).每一个精灵只认识牛_i并且知道牛_i一般走到牛棚_i的最短路经.所以它们在牛_i到牛棚_i之前的最后一条牛路上等牛_i.当然,牛不愿意遇到Gremlins,所以准备找 一条稍微不同的路经从牛棚_1走到牛棚_i.所以,请你为每一头牛_i找出避免精灵的最短路经的长度. 和以往一样, 农场上的M (2 <= M <= 200,000)条双向牛路编号为1-M并且能让所有牛到 达它们的目的地, N

hdu 2433 Travel (最短路径树)

hdu 2433 Travel Description One day, Tom traveled to a country named BGM. BGM is a small country, but there are N (N <= 100) towns in it. Each town products one kind of food, the food will be transported to all the towns. In addition, the trucks will

[BZOJ 1576] 安全路径 最短路径树 路径压缩

题意 给定一张 n 个点 m 条边的图, 保证对于任意的点 i , 从点 1 到点 i 的最短路唯一. 对于任意的点 i , 询问: 将 1 到 i 的最短路中最后一条边删去之后, 从 1 到 i 的最短路 . n <= 100000, m <= 200000 . 分析 首先跑 Dijsktra , 构建出最短路径树. 接下来考虑每条非树边 E[p] = (u, v, d) 对答案的影响, 它能且仅能影响到点 u, v 之上, LCA(u, v) 之下的点的答案. (包括 u, v, 不包括

bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)

4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 426  Solved: 147[Submit][Status][Discuss] Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路 径B为1,3,2,11,路径B

BZOJ4016: [FJOI2014]最短路径树问题

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=4016 最短路+点分治.. 首先要把最短路径树做出来吧..于是先跑一遍spfa,然后bfs一遍就可以建出树了.. 然后点分..对于以重心为根的那棵子树,一棵一棵子树拿出来,维护处dep和dis(到根的距离),然后更新答案. 设g[i][0]为深度为i的路径的最大距离,g[i][1]为当前这个最大距离下的路径个数. 这样维护还算是比较简单的吧... 感人肺腑的是没怎么调,过样例就A了..更感人肺

【bzoj4016】[FJOI2014]最短路径树问题 堆优化Dijkstra+DFS树+树的点分治

题目描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小.注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小).到达该点后按原路返回,然后往其他点走,直到所有点都走过. 可以知道,经过的边会构成一棵最短路径树.请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长

【BZOJ4016】[FJOI2014]最短路径树问题 最短路径树+点分治

[BZOJ4016][FJOI2014]最短路径树问题 Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小.注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小).到达该点后按原路返回,然后往其他点走,直到所有点都走过. 可以知道,经过的边会构成一棵最短