题目链接


题解

题意

  • 给你一个无向图,求两个点之间的一条路径,使路径上的最小值最大

算法:Kruskal最大生成树+倍增lca

分析

  • 首先容易知道,答案一定在该图的最大生成树
  • 之后问题便转换成了树上点\(u\)到\(v\)的简单路径42中最小的边权
  • 经典的树上倍增
  • 用fa[i][j]来表示从第\(i\)个点往上\(2^j\)条边到达的点
  • 用s[i][j]来表示从第\(i\)个点往上\(2^j\)条边中的最小值
  • 答案就是在求lca的过程中统计一下最小值就可以了(具体详见代码)

复杂度

Kruskal \(O(m \log m)\)

倍增 \(O(n \log n)\)

总复杂度 \(O(n \log n + m \log m)\)

代码

  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <cstdio>
  4. #include <algorithm>
  5. using namespace std;
  6. const int MAXN = 50050;
  7. int n, m, q;
  8. int p[MAXN];
  9. int dep[MAXN], vis[MAXN], fa[MAXN][20], s[MAXN][20];
  10. struct Edge
  11. {
  12. int u, v, w;
  13. bool operator < (const Edge &_edge) const
  14. {
  15. return w > _edge.w;
  16. }
  17. }edge[MAXN];
  18. int ecnt;
  19. struct node
  20. {
  21. int v, w;
  22. node *next;
  23. }pool[MAXN], *head[MAXN];
  24. void addedge(int u, int v, int w)
  25. {
  26. node *p = &pool[++ecnt], *q = &pool[++ecnt];
  27. p->v = v, p->w = w, p->next = head[u], head[u] = p;
  28. q->v = u, q->w = w, q->next = head[v], head[v] = q;
  29. }
  30. int find(int x)
  31. {
  32. if(p[x] == 0) return x;
  33. else return p[x] = find(p[x]);
  34. }
  35. bool Union(int x, int y)
  36. {
  37. int px = find(x);
  38. int py = find(y);
  39. if(px == py)
  40. return false;
  41. p[px] = py;
  42. return true;
  43. }
  44. void dfs(int u)
  45. {
  46. int v;
  47. vis[u] = 1;
  48. for(node *p = head[u]; p; p = p->next)
  49. if(!vis[v = p->v])
  50. {
  51. dep[v] = dep[u] + 1;
  52. fa[v][0] = u;
  53. s[v][0] = p->w;
  54. for(int j = 1; fa[v][j - 1] != 0; j++)
  55. fa[v][j] = fa[fa[v][j - 1]][j - 1],
  56. s[v][j] = min(s[v][j - 1], s[fa[v][j - 1]][j - 1]);
  57. //预处理
  58. dfs(v);
  59. }
  60. }
  61. int query(int u, int v)//倍增
  62. {
  63. int ret = 2147483647;//返回值。因为求最小,所以初始赋最大
  64. if(dep[u] < dep[v]) swap(u, v);
  65. for(int i = 15; i >= 0; i--)
  66. if(fa[u][i] != 0 && dep[fa[u][i]] >= dep[v])
  67. ret = min(ret, s[u][i]), u = fa[u][i];//一定要先统计最小值
  68. if(u == v) return ret;
  69. for(int i = 15; i >= 0; i--)
  70. if(fa[u][i] != fa[v][i])
  71. ret = min(ret, min(s[u][i], s[v][i])), //统计最小
  72. u = fa[u][i],
  73. v = fa[v][i];
  74. ret = min(ret, min(s[u][0], s[v][0]));//不要忘了最后还有两条边
  75. return ret;
  76. }
  77. int main()
  78. {
  79. scanf("%d%d", &n, &m);
  80. for(int i = 1; i <= m; i++)
  81. scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
  82. sort(edge + 1, edge + m + 1);
  83. for(int i = 1; i <= m; i++)
  84. if(Union(edge[i].u, edge[i].v))
  85. addedge(edge[i].u, edge[i].v, edge[i].w);
  86. dfs(1);
  87. scanf("%d", &q);
  88. for(int i = 1; i <= q; i++)
  89. {
  90. int u, v;
  91. scanf("%d%d", &u, &v);
  92. if(find(u) != find(v))
  93. {
  94. printf("-1\n");
  95. continue ;
  96. }
  97. printf("%d\n", query(u, v));
  98. }
  99. return 0;
  100. }

题解 【luoguP1967 NOIp提高组2013 货车运输】的更多相关文章

  1. NOIP提高组 2013货车运输

    觉得题目水的离开 不屑的大佬请离开 不会图论的请离开 ……. 感谢您贡献的访问量 ————————————华丽的分割线———————————— 题面: 题目描述 A 国有 n 座城市,编号从 1 到 ...

  2. 【NOIP】提高组2013 货车运输

    [算法]最大生成树+LCA(倍增) [题解]两点间选择一条路径最小值最大的路径,这条路径一定在最大生成树上,因为最大生成树就是从边权最大的边开始加的. 先求原图的最大生成树(森林),重新构图,然后用一 ...

  3. 洛谷P1967 [NOIP2013提高组Day1T2]货车运输

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

  4. 【NOIP2013提高组】货车运输

    货车运输  (truck.cpp/c/pas) [问题描述]  A国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有q辆货车在运输货物,司机们想知道每辆 ...

  5. 洛谷P1966 火柴排队[NOIP提高组2013]

    我确信我应该是做过这道题……就当再写一遍好了. 贪心思想,一番证明得出a和b数组中最小对最小,次小对次小……时解最优.那么先处理出a,b之间的对应关系,然后按照该关系求a或者b的逆序对数量就是答案 / ...

  6. NOIP提高组2013 D2T3 【华容道】

    某王  老师给我们考了一场noip2013的真题...心态爆炸! 题目大意: 有一个n*m的棋盘,每个格子上都有一个棋子,有些格子上的棋子能够移动(可移动的棋子是固定的),棋盘中有一个格子是空的,仍何 ...

  7. NOIP 2013 货车运输【Kruskal + 树链剖分 + 线段树 】【倍增】

    NOIP 2013 货车运输[树链剖分] 树链剖分 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在 ...

  8. NOIP提高组2004 合并果子题解

    NOIP提高组2004 合并果子题解 描述:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消 ...

  9. NOIP提高组历年真题题解

    2018 铺设道路 差分水题,推一下结论就好了. #include<cstdio> #include<algorithm> using namespace std; ],d[] ...

随机推荐

  1. python中的迭代器与生成器

    迭代器 迭代器的引入 假如我现在有一个列表l=['a','b','c','d','e'],我想取列表中的内容,那么有几种方式? 1.通过索引取值 ,如了l[0],l[1] 2.通过for循环取值 fo ...

  2. 数数字 (Digit Counting,ACM/ICPC Dannang 2007 ,UVa1225)

    题目描述:算法竞赛入门经典习题3-3 #include <stdio.h> #include <string.h> int main(int argc, char *argv[ ...

  3. C++clock()延时循环

    函数clock(),返回程序开始执行后所用的系统时间,但是有两个复制问题. 1.clock()返回时间的单位不一定是秒 2.该函数的返回类型在某些系统上可能是Long,也可能是unsigned lon ...

  4. es6从零学习(四):Class的继承

    es6从零学习(四):Class的继承 一:继承的方式 1.Class 可以通过extends关键字实现继承 class Point { } class ColorPoint extends Poin ...

  5. Java实验二实验报告:java面向对象程序设计

    java实验二实验报告 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计模式 实验 ...

  6. c#非界面线程控制控件

    private delegate void FlushCilent(); Invoke(new FlushCilent(databaseConnect));

  7. spring学习(一)——控制反转简单例子

    spring框架是一个开源的轻量级的基于IOC与AOP核心技术的容器框架,主要是解决企业的复杂操作实现. 那IOC与AOP,到底如何解释呢,在看spring视频中,两个专业术语一定必须要懂得. IOC ...

  8. iOS开发JOSNModel<optional>,<convertondemand>,<index>

    指定定义的key的类型 <optional>表示字段可选,例如 //链接字段是可选的,转换的时候允许link未空 @property (nonatomic,strong) NSString ...

  9. pycharm开启代码智能提示和报错提示

    天呐,经历了一大波周折,终于把提示给弄好了,加入没有提示的话,pycharm就是一个空格了,没有什么作用,对我来说,真的是很困难的事情,所以无论如何都要去把这个智能提示给搞好了. 先讲讲我的经历吧.我 ...

  10. PAT L2-005 集合相似度

    https://pintia.cn/problem-sets/994805046380707840/problems/994805070149828608 给定两个整数集合,它们的相似度定义为:/.其 ...