这个题是很经典的生成树问题。第一次接触时对倍增算法的理解还不够透彻,没能打出来正解。

  首先,原题中给出的是一幅图,询问从某点出发到另一点“需要经过的最短边的最大值”。用floyd来解决是可以的,但是数据范围不能承受O(n^3)的复杂度。于是我们考虑:假设原图是连通的,那么我们从某点到另一点,一定至少存在一条路径;而明显有一条路径是最优的,满足它所经过的最小边最大。既然这样,我们能不能把这条路径找出来呢?于是我们想对原图做一些处理。新的图应该满足:

  1. 图仍是连通的。

  2. 任意两点间的一条路径满足上述最优条件。

  于是我们想到了生成树。从贪心的角度考虑,两点之间一定有一条这样的最优路径是最大生成树上的唯一路径。说明:因为最大生成树外的一条边一定小于等于树上的边权,那么它不可能比这条树上路径更优。

  求出MST后,我们要维护的是树上路径的最小值信息。路径本身可以用LCA来搞,可是路径上的信息怎么预处理呢?联想ST算法,我们虽然不能维护任意两点间的信息,但是可以用倍增的思想,维护w(i, k)表示节点i到它的2^k代祖先所需经过的最短路径。w(i, 0)就是生成树上该点入边的权,然后按k从小到大转移,转移方程w(i, k) = min(w(i, k - 1), w(f[i][k-1], k-1))。其中f数组是按倍增法求LCA记录的祖先信息。最后查询时,所求的ans随LCA倍增算法更新最小值即可。

  注意原图是不连通的,我们生成的实际上是一个森林,kruscal算法里维护的并查集可以帮助判断两个点是否在一个联通块内。

代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cctype>
  5. #include <algorithm>
  6. #define maxn 10010
  7. #define maxm 50010
  8. #define inf (int)2e9
  9. using namespace std;
  10. template <typename T>
  11. void read(T &x) {
  12. x = 0;
  13. char ch = getchar();
  14. while (!isdigit(ch)) ch = getchar();
  15. while (isdigit(ch)) {
  16. x = x * 10 + (ch ^ 48);
  17. ch = getchar();
  18. }
  19. return;
  20. }
  21. int n, m, q;
  22. int head[maxn], top = 1;
  23. struct E {
  24. int to, nxt, w;
  25. } edge[maxn << 1];
  26. struct pE {
  27. int u, v, w;
  28. } pedge[maxm];
  29. bool cmp(pE a, pE b) {
  30. return a.w > b.w;
  31. }
  32. inline void insert(int u, int v, int w) {
  33. edge[++top] = (E) {v, head[u], w};
  34. head[u] = top;
  35. }
  36. namespace UFS {
  37. int fa[maxn], rk[maxn];
  38. void init1() {
  39. for (int i = 1; i <= n; ++i)
  40. fa[i] = i;
  41. }
  42. int find(int x) {
  43. if (fa[x] == x) return x;
  44. return fa[x] = find(fa[x]);
  45. }
  46. bool Union(int u, int v) {
  47. u = find(u), v = find(v);
  48. if (u == v) return false;
  49. if (rk[u] < rk[v]) swap(u, v);
  50. fa[v] = u;
  51. rk[u] = max(rk[u], rk[v] + 1);
  52. return true;
  53. }
  54. } using namespace UFS;
  55. void kruscal() {
  56. init1();
  57. sort(pedge + 1, pedge + 1 + m, cmp);
  58. for (int i = 1, cnt = 0; i <= m && cnt < n - 1; ++i) {
  59. int u = pedge[i].u, v = pedge[i].v, w = pedge[i].w;
  60. if (Union(u, v)) {
  61. insert(u, v, w), insert(v, u, w);
  62. ++cnt;
  63. }
  64. }
  65. }
  66. namespace LCA {
  67. const int LG(14);
  68. int w[LG+2][maxn], f[LG+2][maxn], d[maxn];
  69. bool vis[maxn];
  70. void dfs(int u, int pre, int depth) {
  71. d[u] = depth;
  72. f[0][u] = pre;
  73. vis[u] = true;
  74. for (int i = head[u]; i; i = edge[i].nxt) {
  75. int v = edge[i].to;
  76. if (vis[v]) continue;
  77. w[0][v] = edge[i].w;
  78. //          cout << w[0][v];
  79. dfs(v, u, depth + 1);
  80. }
  81. }
  82. void init2() {
  83. for (int i = 1; i <= n; ++i) {
  84. if (vis[i]) continue;
  85. dfs(i, 0, 1);
  86. }
  87. for (int k = 1; k <= LG; ++k)
  88. for (int i = 1; i <= n; ++i) {
  89. f[k][i] = f[k-1][f[k-1][i]];
  90. w[k][i] = min(w[k-1][i], w[k-1][f[k-1][i]]);
  91. //              cout <<w[k][i];
  92. }
  93. }
  94. int query(int u, int v) {
  95. if (find(u) != find(v)) return -1;
  96. int ans = inf;
  97. if (d[u] > d[v]) swap(u, v);
  98. int del = d[v] - d[u];
  99. for (int i = 0; del; ++i, del >>= 1)
  100. if (del & 1)
  101. ans = min(ans, w[i][v]), v = f[i][v];
  102. if (u == v) return ans;
  103. for (int i = LG; i >= 0; --i)
  104. if (f[i][u] != f[i][v]) {
  105. ans = min(ans, min(w[i][u], w[i][v]));
  106. u = f[i][u], v = f[i][v];
  107. }
  108. return min(ans, min(w[0][u], w[0][v]));
  109. }
  110. } using namespace LCA;
  111. int main() {
  112. read(n), read(m);
  113. int u, v, w;
  114. for (int i = 1; i <= m; ++i) {
  115. read(u), read(v), read(w);
  116. if (u != v)
  117. pedge[i] = (pE) {u, v, w};
  118. }
  119. kruscal();
  120. init2();
  121. read(q);
  122. while (q--) {
  123. read(u), read(v);
  124. printf("%d\n", query(u, v));
  125. }
  126. return 0;
  127. }

PS:看了这个题以后觉得树剖貌似是个好东西,有空学习一个。

(7.16)树上路径最小边权用树剖维护的确是很显然的,之后可以打一下。

(8.2)今日一份树剖奉上,开启我的暑假中二学习之旅。

转载于:https://www.cnblogs.com/TY02/p/11132814.html

Luogu P1967 NOIP2013 货车运输相关推荐

  1. poj1330|bzoj3732|noip2013 货车运输 kruskal+倍增lca

    学了一早上倍增,感觉lca还是tarjan好写. poj1330 1 #include <stdio.h> 2 #include <string.h> 3 #include & ...

  2. NOIP2013货车运输

    NOIP2013货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超 ...

  3. 【洛谷P1967】[NOIP2013]货车运输

    货车运输 题目链接 显然,从一点走到另一点的路径中,最小值最大的路径一定在它的最大生成树上 所以要先求出最大生成树,再在生成树上找最近公共祖先,同时求出最小值. 1 #include<iostr ...

  4. 倍增LCA NOIP2013 货车运输

    货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情 ...

  5. 【题解】【洛谷 P1967】 货车运输

    目录 洛谷 P1967 货车运输 原题 题解 思路 代码 洛谷 P1967 货车运输 原题 题面请查看洛谷 P1967 货车运输. 题解 思路 根据题面,假设我们有一个普通的图: 作图工具:Graph ...

  6. CodeVS3287[NOIP2013] 货车运输【Kruskal+倍增求LCA】

    题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过 ...

  7. NOIP2013 货车运输

    传送门 分析 贪心地想,对于两座城市之间,有多条道路,为了每次能多运输一些货物,一定会尽量往边权较大的路走,所以,一些边权较小的路是不会被走过,于是考虑 \(Kruskal\) 重构树,然后在新的图上 ...

  8. [NOIp2013] 货车运输

    比较水的一道题,之前做过类似的,今天没事儿干,写了这个...... 洛谷 P1967 传送门 算法很显然了,先求个生成树,在树上跑倍增...... 有两个地方被卡了,一个是并查集忘赋初值了,还有就是倍 ...

  9. [noip-2013] 货车运输

    https://www.luogu.org/problemnew/show/1967 /*这道题的基本思路在于求最大生成树,构建最大生成树的图然后问题相当于转化成求两点之间一条链上的最小值,因为这是已 ...

最新文章

  1. 安装SQL SERVER2000提示注册表文件被挂起的解决方案
  2. python画直方图代码-python的pyecharts绘制各种图表详细(附代码)
  3. 常见的服务器内存浅析
  4. linux中循环控制语句,3.2.3 Shell脚本--循环控制语句
  5. 【评论】GNU/Linux下有多少是GNU的?
  6. 运营是一个产品价值传递的过程,互联网营销
  7. geojson 河流_GeoJSON 数据类型 | JShare
  8. python selenium 环境_配置Python Selenium环境
  9. 新手入坑自动驾驶,我是这么学习的......
  10. UVA654 LA5508 POJ1079 Ratio【暴力】
  11. 单总线led驱动芯片WS2811在linux下的驱动
  12. 点击图片实现图片放大
  13. 怎样查看计算机注册表上的游戏,win7 32位旗舰版电脑中如何通过注册表修复游戏登陆问题...
  14. carbon安装win7 thinkpad x1_ThinkPad X1 carbon笔记本Win7重装系统步骤详细教程。 重装系统...
  15. 揭秘史上最烂开发项目:苦撑12年,600万+行代码!
  16. 关于Linux、git和github的一些历史事件
  17. ESP32-NVS存储(非易失性存储库)
  18. android华为获取相册,解决华为手机获取相册图片路径为null
  19. 120年奥运历史数据分析
  20. 迷人和漂亮的十几岁的明星

热门文章

  1. 爬虫--用python中requests和urllib模块爬取图片
  2. android开发过程中的错误:the file dx.jar was not loaded from the SDK folder
  3. 使用chardet判断编码方式
  4. 一步一步SharePoint 2007之十二:实现Form认证(2)——创建添加管理帐户的工程
  5. m5310模组数据上传至onenet_一张标准的综合布线系统图及图解注释,带你看懂网络摄像机的数据如何最终上传至核心交换机...
  6. matlab版本的cnn代码,Deep Learning学习 之 CNN代码解析(MATLAB)
  7. 安卓socks5代理客户端_内网Mysql代理浅析
  8. java同步方法完成案例_Java同步代码块和同步方法原理与应用案例详解
  9. linux coredump配置与调试
  10. 阿里敏捷实践| 4个迭代,从批量交付向持续交付转型 1