题目大意

给出一张图,给出q对点,求这两个点间权值最小边最大的路径,输出这个最小边权。

题解

我们先一条一条边建图。当建立的边使得图中形成环时,因为环中的每个节点只考虑是否连通和瓶颈大小,要想互相连通只要一条路就够了,而只有环上的最小边和次小边可能是这条路的瓶颈,且这条路的瓶颈肯定越大越好。故根据贪心,我们可以直接把环中的权值最小边删去。

所以我们就维护一个LCT来随时删边增边,还要用到拆边等方法来统计路径上的值吗?能AC,但太复杂了!

我们从整体考虑,第一段叙述中,每次遇到一个环,其值为S。由于去掉的是最小边,边权w,所以剩余的路径上的边权和S-w是最大的。所以这就是一个最大生成树。所以我们就用Kruskal算法求出最大生成树,再由树上倍增求解即可。注意Kruskal处理的是单向边而不是无向图,所以先Kruskal,再建图。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <cstdarg>
  5. using namespace std;
  6. const int MAX_NODE = 10010, MAX_EDGE = 50010 * 2, MAX_LOG = 20, INF = 0x3f3f3f3f;
  7. struct Node;
  8. struct Edge;
  9. struct Node {
  10. Edge *Head;
  11. Node *Elder[MAX_LOG];
  12. Node *Root;
  13. int MinVal[MAX_LOG];
  14. int Depth;
  15. Node *Father;
  16. }_nodes[MAX_NODE], *CurRoot;
  17. int _vCount;
  18. struct Edge {
  19. Node *From, *To;
  20. Edge *Next;
  21. int Weight;
  22. Edge(Node *from, Node *to, int w):From(from),To(to),Weight(w),Next(NULL){}
  23. Edge() {}
  24. }_edges[MAX_NODE * 2], tempEdges[MAX_EDGE];
  25. int _eCount, tempeCount;
  26. Edge *NewEdge() {
  27. return _edges + (++_eCount);
  28. }
  29. Edge *AddEdge(Node *from, Node *to, int w) {
  30. Edge *e = NewEdge();
  31. e->To = to;
  32. e->From = from;
  33. e->Weight = w;
  34. e->Next = from->Head;
  35. from->Head = e;
  36. return e;
  37. }
  38. void Build(int uId, int vId, int w) {
  39. tempEdges[++tempeCount] = Edge(_nodes + uId, _nodes + vId, w);
  40. }
  41. int Log2(int x) {
  42. int ans = 0;
  43. while (x >>= 1)
  44. ans++;
  45. return ans;
  46. }
  47. void Dfs(Node *cur, Edge *FromFa) {
  48. cur->Root = CurRoot;
  49. if (FromFa == NULL) {
  50. cur->Depth = 1;
  51. cur->MinVal[0] = INF;
  52. }
  53. else {
  54. cur->Elder[0] = FromFa->From;
  55. cur->Depth = cur->Elder[0]->Depth + 1;
  56. cur->MinVal[0] = FromFa->Weight;
  57. for (int i = 1; cur->Elder[i - 1]->Elder[i - 1]; i++) {
  58. cur->Elder[i] = cur->Elder[i - 1]->Elder[i - 1];
  59. cur->MinVal[i] = min(cur->MinVal[i - 1], cur->Elder[i - 1]->MinVal[i - 1]);
  60. }
  61. }
  62. for (Edge *e = cur->Head; e; e = e->Next)
  63. if (e->To != cur->Elder[0])
  64. Dfs(e->To, e);
  65. }
  66. void DfsStart() {
  67. for (int i = 1; i <= _vCount; i++) {
  68. if (!_nodes[i].Depth) {
  69. CurRoot = _nodes + i;
  70. Dfs(CurRoot, NULL);
  71. }
  72. }
  73. }
  74. int Lca(Node *deep, Node *high) {
  75. if (deep->Root != high->Root)
  76. return -1;
  77. int ans = INF;
  78. if (deep->Depth < high->Depth)
  79. swap(deep, high);
  80. int len = deep->Depth - high->Depth;
  81. for (int k = 0; len; k++) {
  82. if ((1 << k)&len) {
  83. ans = min(ans, deep->MinVal[k]);
  84. deep = deep->Elder[k];
  85. len -= (1 << k);
  86. }
  87. }
  88. if (deep == high)
  89. return ans;
  90. for (int k = Log2(deep->Depth); k >= 0; k--) {
  91. if (deep->Elder[k] != high->Elder[k]) {
  92. ans = min(ans, deep->MinVal[k]);
  93. ans = min(ans, high->MinVal[k]);
  94. deep = deep->Elder[k];
  95. high = high->Elder[k];
  96. }
  97. }
  98. ans = min(ans, deep->MinVal[0]);
  99. ans = min(ans, high->MinVal[0]);
  100. return ans;
  101. }
  102. bool CmpEdge(Edge a, Edge b) {
  103. return a.Weight > b.Weight;
  104. }
  105. Node *FindFather(Node *cur) {
  106. return cur == cur->Father ? cur : cur->Father = FindFather(cur->Father);
  107. }
  108. void Join(Node *root1, Node *root2) {
  109. root1->Father = root2;
  110. }
  111. void Kruskal() {
  112. sort(tempEdges + 1, tempEdges + tempeCount + 1, CmpEdge);
  113. for (int i = 1; i <= _vCount; i++)
  114. _nodes[i].Father = _nodes + i;
  115. for (int i = 1; i <= tempeCount; i++) {
  116. Edge e = tempEdges[i];
  117. Node *root1 = FindFather(e.From), *root2 = FindFather(e.To);
  118. if (root1 != root2) {
  119. AddEdge(e.From, e.To, e.Weight);
  120. AddEdge(e.To, e.From, e.Weight);
  121. Join(root1, root2);
  122. }
  123. }
  124. }
  125. int main() {
  126. int totEdge;
  127. scanf("%d%d", &_vCount, &totEdge);
  128. for (int i = 1; i <= totEdge; i++) {
  129. int u, v, w;
  130. scanf("%d%d%d", &u, &v, &w);
  131. Build(u, v, w);
  132. }
  133. Kruskal();
  134. DfsStart();
  135. int queryCnt;
  136. scanf("%d", &queryCnt);
  137. while (queryCnt--) {
  138. int u, v;
  139. scanf("%d%d", &u, &v);
  140. printf("%d\n", Lca(_nodes + u, _nodes + v));
  141. }
  142. return 0;
  143. }

luogu1967 货车运输 最大瓶颈生成树的更多相关文章

  1. NOIP2013 货车运输(最大生成树,倍增)

    NOIP2013 货车运输(最大生成树,倍增) A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道 ...

  2. NOIP2013 货车运输 (最大生成树+树上倍增LCA)

    死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...

  3. 「NOIP2013」「LuoguP1967」货车运输(最大生成树 倍增 LCA

    题目描述 AA国有nn座城市,编号从 11到nn,城市之间有 mm 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最 ...

  4. $Noip2013/Luogu1967$ 货车运输 最大生成树+倍增$lca$

    $Luogu$ $Sol$ 首先当然是构建一棵最大生成树,然后对于一辆货车的起点和终点倍增跑$lca$更新答案就好.记得预处理倍增的时候不仅要处理走了$2^i$步后是那个点,还有这中间经过的路径权值的 ...

  5. [洛谷 P1967] 货车运输 (最大生成树 lca)

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

  6. [NOIP2013/Codevs3287]货车运输-最小[大]生成树-树上倍增

    Problem 树上倍增 题目大意 给出一个图,给出若干个点对u,v,求u,v的一条路径,该路径上最小的边权值最大. Solution 看到这个题第一反应是图论.. 然而,任意路径最小的边权值最大,如 ...

  7. [luogu1967][货车运输]

    题目链接 题意: 其实题目的意思就是问从x到y权值最小的路的权值最大能是多少. 思路: 首先可以先把这张图变成一棵树.因为那些更小的点肯定是不跑更优秀,而且题目没有要求路程,所以生成一棵树,只要能保证 ...

  8. 货车运输(最大生成树+倍增LCA)

    看到第一篇题解的神奇码风--我决定发一篇码风正常的题解造福人类 这题的做法也非常经典,最大生成树\(+LCA\),相当于先贪心一下,在LCA的时候记录一下当前最小的边权 顺便吐槽一下最后一个测试点: ...

  9. Luogu P1967 货车运输 倍增+最大生成树

    看见某大佬在做,决定补一发题解$qwq$ 首先跑出最大生成树(注意有可能不连通),然后我们要求的就是树上两点间路径上的最小边权. 我们用倍增的思路跑出来$w[u][j]$,表示$u$与的它$2^j$的 ...

随机推荐

  1. 最近积累的JS 东西,分享一下

    js 关闭页面 var browserName=navigator.appName; if (browserName=="Netscape") { window.open('',' ...

  2. nginx编译安装新模块

    nginx的模块是需要重新编译nginx,而不是像apache一样配置文件引用.so 这里以安装第三方ngx_http_google_filter_module模块为例 下载第三方扩展模块ngx_ht ...

  3. Java创建Excel-DEMO

    import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.Out ...

  4. ASP.NET MD5加密

    protected void Button1_Click(object sender, EventArgs e) { string pwd = TextBox2.Text.Trim(); Respon ...

  5. Mysql 设置起始值

    alter table t_tszj_pet_activity AUTO_INCREMENT=10000;   设置 id 从10000 开始

  6. java将父类所有的属性COPY到子类中

    public class FatherToChildUtils { /* * 将父类所有的属性COPY到子类中. * 类定义中child一定要extends father: * 而且child和fat ...

  7. Spring AOP --JDK动态代理方式

    我们知道Spring是通过JDK或者CGLib实现动态代理的,今天我们讨论一下JDK实现动态代理的原理. 一.简述 Spring在解析Bean的定义之后会将Bean的定义生成一个BeanDefinit ...

  8. BZOJ 3631: [JLOI2014]松鼠的新家 树上差分 + LCA

    Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在“树”上.松鼠想邀 ...

  9. vue-router 懒加载

    懒加载:也叫延迟加载,即在需要的时候进行加载,按需加载. 那vue 为什么需要懒加载呢? 使用 vue-cli构建的项目,在默认情况下,执行 npm run build  会将所有的 js代码打包为一 ...

  10. [模板]FFT

    郝神并没有令我明白这个. 但是巨神的题解太强了. #include <iostream> #include <complex> #include <cmath> # ...