题面:

传送门

思路:

既然最后一条边不能走,那么就一定是换了一条路,一条不经过这最后一条边的路

如果想要这条路最短,那么其在路上一定尽可能多地走了最短路径

因此,我们对这张图跑一遍从1开始的单源最短路,并建立出最短路径树

那么新的路径(1->u)一定是这样构成的:(1->v)+edge(v,w)+(w->u),其中w是u在最短路径树上的后代

那么,我们对于每一条非树边(u,v),其树上路径上所有点(除了lca)的答案,都可以被dis[u]+dis[v]+w(u,v)-dis[路径上的点]来更新

然而,直接每一次这样更新,时间效率肯定不行

对上述的结论进一步分析,可以发现,实际上dis[u]+dis[v]+w(u,v)对于每条非树边(u,v)固定

因此可以把dis[u]+dis[v]+w(u,v)排序,对于每一条非树边依次操作,并且使用并查集来跳过已经更新过得边

总时间复杂度:dij O(nlogn),排序 O(mlogm) 更新答案 O(n)

Code:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
struct edge{
int to,w,next;
}e[];
struct new_edge{
int from,to,w;
}x[];
struct node{
int num,fa;
vector<int>son;
}a[];
int n,m,first[],pre[],dis[],f[],ans[];
bool vis[];
void spfa(){
int i,u,v,w;
queue<int>q;memset(dis,,sizeof(dis));
q.push();pre[]=;dis[]=;
while(!q.empty()){
u=q.front();q.pop();vis[u]=;
for(i=first[u];~i;i=e[i].next){
v=e[i].to;w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;pre[v]=u;
if(!vis[v]){
vis[v]=;q.push(v);
}
}
}
}
}
bool cmp(new_edge l,new_edge r){
return l.w<r.w;
}
int find(int x){
return ((f[x]==x)?x:f[x]=find(f[x]));
}
int aa[],bb[],cc[];
int main(){
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
memset(first,-,sizeof(first));
memset(ans,-,sizeof(ans));
int i,j,t1,t2,t3,l,r;
scanf("%d%d",&n,&m);
for(i=;i<=m;i++){
scanf("%d%d%d",&t1,&t2,&t3);
e[i*-].to=t2;e[i*-].next=first[t1];e[i*-].w=t3;first[t1]=i*-;
e[i*].to=t1;e[i*].next=first[t2];e[i*].w=t3;first[t2]=i*;
aa[i]=t1;bb[i]=t2;cc[i]=t3;
}
spfa();
// for(i=1;i<=n;i++) cout<<pre[i]<<ends<<dis[i]<<endl;
// for(i=1;i<=m;i++) cout<<aa[i]<<ends<<bb[i]<<ends<<cc[i]<<endl;
// cout<<"end of spfa"<<endl;
for(i=;i<=n;i++){
a[i].num=i;f[i]=i;
a[i].fa=pre[i];
if(i!=) a[pre[i]].son.push_back(i);
}
int cnt=;
for(i=;i<=m;i++){
if(pre[aa[i]]==bb[i]||pre[bb[i]]==aa[i]) continue;
// cout<<aa[i]<<ends<<bb[i]<<ends<<cc[i]<<endl;
x[++cnt].from=aa[i];x[cnt].to=bb[i];x[cnt].w=dis[aa[i]]+dis[bb[i]]+cc[i];
}
// cout<<"end2"<<endl;
sort(x+,x+cnt+,cmp);
for(i=;i<=cnt;i++){
l=find(x[i].from);r=find(x[i].to);
while(l!=r){
if(dis[l]<dis[r]) swap(l,r);
ans[l]=x[i].w-dis[l];
f[l]=pre[l];l=find(l);
}
}
for(i=;i<=n;i++) printf("%d\n",ans[i]);
}

[usaco jan 09] 安全路径 travel [最短路径树]的更多相关文章

  1. [usaco jan 09] 气象牛 baric [dp]

    题面: 传送门 思路: 题意有点绕,实际上就是给你一个计算规则,让你取最少的元素,通过这个计算方式,得到一个小于指定误差上限的结果 这个规则分为三个部分,这里分别用pre,sum,suf表示 因为给定 ...

  2. [BZOJ1576] [BZOJ3694] [USACO2009Jan] 安全路径(最短路径+树链剖分)

    [BZOJ1576] [BZOJ3694] [USACO2009Jan] 安全路径(最短路径+树链剖分) 题面 BZOJ1576和BZOJ3694几乎一模一样,只是BZOJ3694直接给出了最短路树 ...

  3. [BZOJ 1576] [Usaco2009 Jan] 安全路经Travel 【树链剖分】

    题目链接: BZOJ - 1576 题目分析 首先Orz Hzwer的题解. 先使用 dijikstra 求出最短路径树. 那么对于一条不在最短路径树上的边 (u -> v, w) 我们可以先沿 ...

  4. 【最短路径树】51nod1443 路径和树

    并不是什么高端操作并且一些模型会用到 Description 给定一幅无向带权连通图G = (V, E) (这里V是点集,E是边集).从点u开始的最短路径树是这样一幅图G1 = (V, E1),其中E ...

  5. 安全路径——最短路径树+dsu缩边

    题目描述 思路 首先想到$dijkstra$跑完之后$build$一棵最短路径树.要找到每个节点i到根的满足要求的最短路,考虑把一些非树边加进去. 对于非树边$(u,v)$,因为节点i上方的边被占领, ...

  6. bzoj 4016: [FJOI2014]最短路径树问题

    bzoj4016 最短路路径问题 Time Limit: 5 Sec Memory Limit: 512 MB Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点 ...

  7. [BZOJ4016][FJOI2014]最短路径树问题

    [BZOJ4016][FJOI2014]最短路径树问题 试题描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长 ...

  8. HDU4871 Shortest-path tree(最短路径树 + 树的点分治)

    题目大概要先求一张边有权的图的根为1的最短路径树,要满足根到各点路径序列的字典序最小:然后求这棵最短路径树包含k个结点的最长路径的长度和个数. 首先先构造出这棵字典序最小的最短路径树..好吧,我太傻逼 ...

  9. POJ3013 Big Christmas Tree(最短路径树)

    题目大概说给一张点和边都有权的图,现在要求其一棵以1结点为根的生成树使树的边权和最小,树边权 = 对应的图边权 * 树边末端点为根的子树所有结点对于图顶点的点权和. 要求∑(边权*子树点权和),等价于 ...

随机推荐

  1. Problem G: 圆周率

    Problem G: 圆周率 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 155  Solved: 99[Submit][Status][Web Bo ...

  2. Java控制语句例题,for循环语句,if条件语句等,Scanner类与Random类,Math.max()方法

    例题:编写程序,生成5个1至10之间的随机整数,并打印结果到控制台 import java.util.Random;class demo09 { public static void main(Str ...

  3. python查看安装包

    D:\Python27\Scripts>pip listbackports.ssl-match-hostname (3.4.0.2)basicauth (0.2)certifi (14.5.14 ...

  4. swl模拟

    #import <Foundation/Foundation.h> #define NSLog(FORMAT, ...) printf("%s\n", [[NSStri ...

  5. js基础之语言部分必须要掌握的五大方阵

    javascript基础部分可以从"数组, 函数, 作用域, 对象, 标准库"这5大方阵进行学习: (一).数组 数组的声明(2种):; a,自变量声明 var a = ['a', ...

  6. C++大数问题

    1.大数的加法 语法:add(char a[],char b[],char s[]); 参数: a[]:被加数,用字符串表示,位数不限 b[]:加数,用字符串表示,位数不限 s[]:结果,用字符串表示 ...

  7. Linux网络编程之"获取网络天气信息"

    需求分析: 1.需要Linux c 网络编程基础, 2.需要了解 http 协议 3.需要天气信息相关api(可以从阿里云上购买,很便宜的!) 4.需要cJSON解析库(因为获取到的天气信息一般是用c ...

  8. Mysql的一些纪要

    unsigned 整型的每一种都分无符号(unsigned)和有符号(signed)两种类型(float和double总是带符号的),在默认情况下声明的整型变量都是有符号的类型(char有点特别),如 ...

  9. sendmail安装与配置

    一.安装sendmail与mail 1.安装sendmail:  1) centos下可以安装命令:yum -y install sendmail 2) 安装完后启动sendmail命令:servic ...

  10. 项目实战14.1—ELK 企业内部日志分析系统

    本文收录在Linux运维企业架构实战系列 一.els.elk 的介绍 1.els,elk els:ElasticSearch,Logstash,Kibana,Beats elk:ElasticSear ...