Description

有一张n个点m条边的无向图,求删去任意一条边后,从S到T的最短距离的最大值

n, m ≤ 2×1052 \times 10^52×105

Solution

这道题是[USACO09JAN]Safe Travel的变形,然后这是题解

Safe Travel这道题的普遍做法是并查集树剖,但学长的PDF里提到的是题解讲的可并堆做法,所以我就没采用前两种

然后讲回传送门这题,
首先考虑怎么求删掉一条边后相邻两个点到 T 的最短距离。建出最短路树,如果删掉的不是连向父亲的边,则最短路不变,否则就和Safe Travel一样了

那么怎么求出最终答案呢?可以在图上DP一下

对每个点 u,记 d(u) 表示 u 到 T 的最短路,e(u) 表示删掉它和最短路树上父亲的边后的最短路。令 dp(u) 表示 S = u 时的答案。每次找到 dp 值最小的点来更新其它的点的 dp 值即可。用 u 更新 v 时的转移为 dp(v) =min { max(dp(u) + w(u, v), u == parent v?e(v) : d(v)) }。

Code

//一定不能把S,T反过来,不然就全WA了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pr;
const int inf=0x7fffffff;
const int N=2e5+5;
const int M=2e5+5;
struct Edge{int v,w,nxt,tr;
}edge[M<<1];
int head[N],cnt,vis[N],pre[N];ll dis[N];
priority_queue<pr,vector<pr> ,greater<pr> > q;
int siz[N],dfn[N],ind,parent[N];ll e[N],dp[N];
struct Node{int to,ls,rs,fa,dist;ll val;
}t[M*20];
int tot,rt[N];
int n,m;
void add_edge(int u,int v,int w){edge[++cnt].v=v;edge[cnt].w=w;edge[cnt].nxt=head[u];head[u]=cnt;
}
void dijskra(int s){for(int i=1;i<=n;i++) dis[i]=inf;memset(vis,0,sizeof(vis));dis[s]=0;q.push(make_pair(0,s));while(!q.empty()){pr tmp=q.top();q.pop();int u=tmp.second;if(vis[u]) continue;vis[u]=1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v,w=edge[i].w;if(dis[v]>dis[u]+1ll*w){dis[v]=dis[u]+1ll*w;pre[v]=i;q.push(pr(dis[v],v));}}}
}
void build(){//建最短路树 for(int i=1;i<=n;i++)if(pre[i]) edge[pre[i]].tr=1;
}
int merge(int a,int b){if(!a||!b) return a+b;if(t[a].val>t[b].val) swap(a,b);t[a].rs=merge(t[a].rs,b);t[t[a].rs].fa=a;if(t[t[a].ls].dist<t[t[a].rs].dist) swap(t[a].ls,t[a].rs);t[a].dist=t[t[a].rs].dist+1;return a;
}
int pop(int a){return merge(t[a].ls,t[a].rs);
}
bool check(int u,int v){return dfn[v]>=dfn[u]&&dfn[v]<=dfn[u]+siz[u]-1;
}
void dfs(int u,int fa){dfn[u]=++ind;siz[u]=1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa||!edge[i].tr) continue;parent[v]=u;dfs(v,u);rt[u]=merge(rt[u],rt[v]);siz[u]+=siz[v];}for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa||edge[i].tr) continue;//(u,fa)也是树边,不考虑 t[++tot]=(Node){v,0,0,tot,0,dis[u]+dis[v]+edge[i].w};rt[u]=merge(rt[u],tot); }while(check(u,t[rt[u]].to)) rt[u]=pop(rt[u]);e[u]=rt[u]?t[rt[u]].val-dis[u]:inf;
}
void get_ans(int s){for(int i=1;i<=n;i++) dp[i]=inf;memset(vis,0,sizeof(vis));dp[s]=0;q.push(make_pair(0,s));while(!q.empty()){pr tmp=q.top();q.pop();int u=tmp.second;if(vis[u]) continue;vis[u]=1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v,w=edge[i].w;int t=max(dp[u]+w,parent[v]==u?e[v]:dis[v]);if(dp[v]>t){dp[v]=t;q.push(pr(dp[v],v));}}}
}
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int u,v,w;scanf("%d%d%d",&u,&v,&w);add_edge(u,v,w);add_edge(v,u,w);}dijskra(n);build();tot=n;dfs(n,0);get_ans(n);if(dp[1]==inf) printf("%d\n",-1); else printf("%lld\n",dp[1]);return 0;
}

传送门(最短路树+可并堆)相关推荐

  1. BZOJ1975[Sdoi2010]魔法猪学院——可持久化可并堆+最短路树

    题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界的世界本原有了很多的了解:众所周知,世界是由元素构成的:元素与 ...

  2. CodeForces - 1076D Edge Deletion(最短路+贪心/最短路树+bfs)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边的带权无向图,设 d[i]d[ i ]d[i] 为从点 1 到点 i 的最短路,现在要求保留最多 k 条边,使得新图中 d′[i]=d[i]d ...

  3. Loj#2769-「ROI 2017 Day 1」前往大都会【最短路树,斜率优化】

    正题 题目链接:https://loj.ac/p/2769 题目大意 给出nnn个点mmm条地铁线路,每条线路是一条路径. 求111到nnn的最短路且在最短路径的情况下相邻换乘点的距离平方和最大. 1 ...

  4. 【CodeForces - 545 ABCDE套题训练题解】贪心, 构造,模拟,dp,最短路树(Dijkstra+变形)

    A: 题干: Input The first line contains integer n (1 ≤ n ≤ 100) - the number of cars. Each of the next  ...

  5. Educational Codeforces Round 54 (Rated for Div. 2): D. Edge Deletion(最短路树)

    题意: 给你n个点m条边的无向图,其中1号节点是市中心,你现在最多只能保留k条边,并要求所有点到市中心的最短路尽量不变(也就是说设点i到点1的最短路为di,那么删边之后,要保证尽可能多的点,它到1的最 ...

  6. Berland and the Shortest Paths CodeForces - 1005F(最短路树)

    最短路树就是用bfs走一遍就可以了 d[v] = d[u] + 1 表示v是u的前驱边 然后遍历每个结点 存下它的前驱边 再用dfs遍历每个结点 依次取每个结点的某个前驱边即可 #include &l ...

  7. bzoj3694:最短路(最短路树+并查集)

    3694:最短路 时间限制: 1000 ms 内存限制: 262144 KB 题目描述 给出一个 n n n个点m" role="presentation" style= ...

  8. * Dijkstra 堆优化

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/Mashiro_ylb/article/ ...

  9. 【讲解 + 模板】Dijkstra迪杰斯特拉+堆优化

    Dijkstra迪杰斯特拉+堆优化 众所周知,朴素的迪杰斯特拉的时间复杂度为O(n^2),这在某些题目当中是会超时的.但如果在迪杰斯特拉中枚举每个最短边时加入堆优化,则迪杰斯特拉的效率则会大大提高. ...

最新文章

  1. 今晚8点直播 | 深入浅出理解A3C强化学习
  2. 【20160924】GOCVHelper MFC增强算法(1)
  3. oracle查看用户密码时间限制
  4. mongodb 监控命令mongostat
  5. lambda中使用filter过滤
  6. 工业交换机的定义和应用
  7. ue4 运行禁用鼠标_从零开始——三:关闭电脑无用服务提高运行速度
  8. 部份API学习笔记(Math,System,Object,Date,SimpleDateFormat)
  9. java中枚举表示数据状态
  10. Emacs 中英文字体设置
  11. 在Python中从头开始迭代本地搜索
  12. pre和code的区别
  13. 搜索引擎漫谈以及 Zinc 简介
  14. 如何打印计算机文档目录,word怎么把目录显示出来
  15. 笔记本光驱改固态硬盘装系统小记
  16. 超级万能计算机在线应用,超级万能计算器手机版
  17. http协议如何获取请求参数
  18. 一份来自区块链行业的《高考志愿填报指南》
  19. NLP自然语言处理-机器学习和自然语言处理介绍(五)
  20. JavaScript---网络编程(2)-函数与数组

热门文章

  1. sql 日期和当前日期时间差_详解PostgreSQL 如何获取当前日期时间
  2. js重新渲染div_前端工程师必备:从浏览器的渲染到性能优化
  3. mysql java驱动 ibm_JDBC驱动汇总
  4. 解决Spring boot整合mybatis,xml资源文件放置及路径配置问题
  5. 每天都在红绿灯前面梭行,不如自己来实现个红绿灯?
  6. C++string容器-字符串拼接
  7. FatMouse and Cheese HDU - 1078(记忆化搜索入门模板)
  8. 获取壁纸设置背景android,【Android学习】获取Bing 15天前到明天的壁纸,并设置为背景...
  9. leetcode 岛屿的个数
  10. 【清华集训2014】Sum)(类欧几里得算法)