BZOJ1576: [Usaco2009 Jan]安全路经Travel(最短路 并查集)
题意
给你一张无向图,保证从1号点到每个点的最短路唯一。对于每个点求出删掉号点到它的最短路上的最后一条边(就是这条路径上与他自己相连的那条边)后1号点到它的最短路的长度
Sol
emmm,考场上想了个贪心开心的飞起然而只多得了10分qwq
正解比较神仙。
首先把最短路树建出来,考虑一条非树边$(u, v)$什么时候能更新答案
结论是:除了他们的LCA外的子树内其他都可以更新,且新的权值为$dis[u] + dis[v] + w(u, v) - dis[x]$,$x$表示新节点
这样我们把所有的边按照$dis[u] + dis[v] + w(u, v)$排序,显然,一个点如果被更新过那么就再也不会被更新了。
用并查集把已经更新过的点缩起来即可
这题的关键是要发现非树边与答案之间的性质。。
- #include<cstdio>
- #include<vector>
- #include<queue>
- #include<cstring>
- #include<algorithm>
- #define Pair pair<int, int>
- #define MP(x, y) make_pair(x, y)
- #define fi first
- #define se second
- using namespace std;
- const int MAXN = 1e6 + , INF = 1e9 + ;
- inline int read() {
- char c = getchar(); int x = , f = ;
- while(c < '' || c > '') {if(c == '-') f = -; c = getchar();}
- while(c >= '' && c <= '') x = x * + c - '', c = getchar();
- return x * f;
- }
- int N, M;
- vector<Pair> v[MAXN];
- struct Edge {
- int u, v, w;
- }E[MAXN];
- int num = ;
- int dis[MAXN], top[MAXN], vis[MAXN], cnt = , ans[MAXN];
- void Dij() {
- memset(dis, 0x7f, sizeof(dis));
- dis[] = ;
- priority_queue<Pair> q; q.push(MP(, ));
- while(!q.empty()) {
- int p = q.top().se; q.pop();
- if(vis[p]) continue; vis[p] = ;
- for(int i = ; i < v[p].size(); i++) {
- int to = v[p][i].fi, w = v[p][i].se;
- if(dis[to] > dis[p] + w && (!vis[to])) {
- top[to] = p;
- dis[to] = dis[p] + w;
- q.push(MP(-dis[to], to));
- }
- }
- }
- }
- int comp(const Edge &a, const Edge &b) {
- return dis[a.u] + dis[a.v] + a.w < dis[b.u] + dis[b.v] + b.w;
- }
- int fa[MAXN];
- int unionn(int x, int y) {
- fa[x] = y;
- }
- int Find(int x) {
- if(fa[x] == x) return fa[x];
- else return fa[x] = Find(fa[x]);
- }
- int solve(int x, int y, int w) {
- while((x = Find(x)) != (y = Find(y))) {
- //int dx = dis[x], dy = dis[y];
- if(dis[x] < dis[y]) swap(x, y);
- ans[x] = w - dis[x];
- x = (fa[x] = top[x]);
- cnt++;
- }
- }
- int main() {
- N = read(); M = read();
- for(int i = ; i <= M; i++) {
- int x = read(), y = read(), z = read();
- v[x].push_back(MP(y, z));
- v[y].push_back(MP(x, z));
- }
- Dij();
- for(int i = ; i <= N; i++) {
- fa[i] = i;
- for(int j = ; j < v[i].size(); j++) {
- int to = v[i][j].fi, w = v[i][j].se;
- if(top[to] == i || top[i] == to) continue;
- E[++num] = (Edge) {i, to, w};
- }
- }
- sort(E + , E + num + , comp);
- for(int i = ; i <= num; i++) {
- solve(E[i].u, E[i].v, dis[E[i].u] + dis[E[i].v] + E[i].w);
- if(cnt == N - ) break;
- }
- for(int i = ; i <= N; i++)
- printf("%d\n", ans[i] ? ans[i] : -);
- return ;
- }
BZOJ1576: [Usaco2009 Jan]安全路经Travel(最短路 并查集)的更多相关文章
- 【BZOJ1576】[Usaco2009 Jan]安全路经Travel 最短路+并查集
[BZOJ1576][Usaco2009 Jan]安全路经Travel Description Input * 第一行: 两个空格分开的数, N和M * 第2..M+1行: 三个空格分开的数a_i, ...
- BZOJ.1576.[Usaco2009 Jan]安全路经Travel(树形DP 并查集)
题目链接 BZOJ 洛谷 先求最短路树.考虑每一条非树边(u,v,len),设w=LCA(u,v),这条边会对w->v上的点x(x!=w)有dis[u]+dis[v]-dis[x]+len的距离 ...
- 【思维题 并查集 图论】bzoj1576: [Usaco2009 Jan]安全路经Travel
有趣的思考题 Description Input * 第一行: 两个空格分开的数, N和M * 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i Output * 第1..N-1行: 第 ...
- BZOJ1576 [Usaco2009 Jan]安全路经Travel
首先用Dijkstra做出最短路生成树,设dis[p]为1到p点的最短路长度 对于一条不在生成树上的边u -> v,不妨设fa为u.v的lca 则一fa到v的路径上的任意点x都可以由u达到,走的 ...
- BZOJ1576: [Usaco2009 Jan]安全路经Travel(树链剖分)
Description Input * 第一行: 两个空格分开的数, N和M * 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i Output * 第1..N-1行: 第i行包含一个数 ...
- [BZOJ1576] [Usaco2009 Jan]安全路经Travel(堆优化dijk + (并查集 || 树剖))
传送门 蒟蒻我原本还想着跑两边spfa,发现不行,就gg了. 首先这道题卡spfa,所以需要用堆优化的dijkstra求出最短路径 因为题目中说了,保证最短路径有且只有一条,所以可以通过dfs求出最短 ...
- bzoj 1576: [Usaco2009 Jan]安全路经Travel 树链剖分
1576: [Usaco2009 Jan]安全路经Travel Time Limit: 10 Sec Memory Limit: 64 MB Submit: 665 Solved: 227[Sub ...
- bzoj 1576: [Usaco2009 Jan]安全路经Travel——并查集+dijkstra
Description Input * 第一行: 两个空格分开的数, N和M * 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i Output * 第1..N-1行: 第i行包含一个数 ...
- BZOJ 1576: [Usaco2009 Jan]安全路经Travel
日常自闭半小时后看题解,太弱了qwq. 感觉这道题还是比较难的,解法十分巧妙,不容易想到. 首先题目说了起点到每个点的最短路都是唯一的,那么对这个图求最短路图必定是一棵树,而且这棵树是唯一的. 那么我 ...
随机推荐
- inode与block
1. inode 是索引节点,在每个Linux存储设备或者存储设备的分区被格式化为ext4文件系统,一般生成两个部分:第一部分为inode,第二部分为block inode:存放的是 ...
- ASP.NET相关
1.委托:把一个方法当作参数传到另一个方法中 扩展方法:1.静态类 2.静态方法 3.this关键字 using System; using System.Collections.Generic; u ...
- c语言字符串操作总结(转)
本文转自:http://www.jb51.net/article/37410.htm 1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 s ...
- java如何调用服务端的WSDL接口
如何使用http://192.168.0.170:8090/kaoshi?wsdl调用服务端暴露在外面可以使用的接口 1.首先创建调用ws的web项目,就一个普通的web项目就行: 2.通过eclip ...
- mysql语句删除重复数据,保留一条;查询所有重复数据;查询重复数据的一条,
//显示重复的所有条 SELECT * FROM 表名 WHERE (字段1,字段2,...) IN (SELECT 字段1,字段2,...FROM 表名 GROUP BY 字段1,字段2,... H ...
- springboot 学习笔记(五)
(五)springboot整合thymeleaf模板,实现简单的登陆 1.修改上一节笔记中的user表,新增一个password字段,同时要求username为UNIQUE,以实现登陆校验,表结构如下 ...
- 数据库(DBUtils)
DBUtils和连接池 今日内容介绍 u DBUtils u 连接池 第1章 DBUtils 如果只使用JDBC进行开发,我们会发现冗余代码过多,为了简化JDBC开发,本案例我们讲采用apache c ...
- .net core +mysqlSugar(最为简单的增删改查)
首先建立.net Core API - empty 这个就不说了 然后创建新的Controller 记得添加路由 [Route("api/Users")] 然后在Nuget Pac ...
- Vue系列:关于侵权前言
因为一开始学习 Vue 的时候,秉持的是"好记性不如烂笔头"的思想,所以这些知识点都是当时查阅然后选择性摘录下来的. 当时并没有很刻意去记录原文出处(现在我知错了..),所以..如 ...
- 零基础逆向工程31_Win32_05_提取图标_修改标题
在程序中使用图标 1.加载图标 HICON hIcon; hIcon = LoadIcon (hAppInstance, MAKEINTRESOURCE (IDI_ICON)); hAppInstan ...