题目大意

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

题解

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

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

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

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdarg>
using namespace std; const int MAX_NODE = 10010, MAX_EDGE = 50010 * 2, MAX_LOG = 20, INF = 0x3f3f3f3f; struct Node;
struct Edge; struct Node {
Edge *Head;
Node *Elder[MAX_LOG];
Node *Root;
int MinVal[MAX_LOG];
int Depth;
Node *Father;
}_nodes[MAX_NODE], *CurRoot;
int _vCount; struct Edge {
Node *From, *To;
Edge *Next;
int Weight;
Edge(Node *from, Node *to, int w):From(from),To(to),Weight(w),Next(NULL){}
Edge() {}
}_edges[MAX_NODE * 2], tempEdges[MAX_EDGE];
int _eCount, tempeCount; Edge *NewEdge() {
return _edges + (++_eCount);
} Edge *AddEdge(Node *from, Node *to, int w) {
Edge *e = NewEdge();
e->To = to;
e->From = from;
e->Weight = w;
e->Next = from->Head;
from->Head = e;
return e;
} void Build(int uId, int vId, int w) {
tempEdges[++tempeCount] = Edge(_nodes + uId, _nodes + vId, w);
} int Log2(int x) {
int ans = 0;
while (x >>= 1)
ans++;
return ans;
} void Dfs(Node *cur, Edge *FromFa) {
cur->Root = CurRoot;
if (FromFa == NULL) {
cur->Depth = 1;
cur->MinVal[0] = INF;
}
else {
cur->Elder[0] = FromFa->From;
cur->Depth = cur->Elder[0]->Depth + 1;
cur->MinVal[0] = FromFa->Weight;
for (int i = 1; cur->Elder[i - 1]->Elder[i - 1]; i++) {
cur->Elder[i] = cur->Elder[i - 1]->Elder[i - 1];
cur->MinVal[i] = min(cur->MinVal[i - 1], cur->Elder[i - 1]->MinVal[i - 1]);
}
}
for (Edge *e = cur->Head; e; e = e->Next)
if (e->To != cur->Elder[0])
Dfs(e->To, e);
} void DfsStart() {
for (int i = 1; i <= _vCount; i++) {
if (!_nodes[i].Depth) {
CurRoot = _nodes + i;
Dfs(CurRoot, NULL);
}
}
} int Lca(Node *deep, Node *high) {
if (deep->Root != high->Root)
return -1;
int ans = INF;
if (deep->Depth < high->Depth)
swap(deep, high);
int len = deep->Depth - high->Depth;
for (int k = 0; len; k++) {
if ((1 << k)&len) {
ans = min(ans, deep->MinVal[k]);
deep = deep->Elder[k];
len -= (1 << k);
}
}
if (deep == high)
return ans;
for (int k = Log2(deep->Depth); k >= 0; k--) {
if (deep->Elder[k] != high->Elder[k]) {
ans = min(ans, deep->MinVal[k]);
ans = min(ans, high->MinVal[k]);
deep = deep->Elder[k];
high = high->Elder[k];
}
}
ans = min(ans, deep->MinVal[0]);
ans = min(ans, high->MinVal[0]);
return ans;
} bool CmpEdge(Edge a, Edge b) {
return a.Weight > b.Weight;
} Node *FindFather(Node *cur) {
return cur == cur->Father ? cur : cur->Father = FindFather(cur->Father);
} void Join(Node *root1, Node *root2) {
root1->Father = root2;
} void Kruskal() {
sort(tempEdges + 1, tempEdges + tempeCount + 1, CmpEdge);
for (int i = 1; i <= _vCount; i++)
_nodes[i].Father = _nodes + i;
for (int i = 1; i <= tempeCount; i++) {
Edge e = tempEdges[i];
Node *root1 = FindFather(e.From), *root2 = FindFather(e.To);
if (root1 != root2) {
AddEdge(e.From, e.To, e.Weight);
AddEdge(e.To, e.From, e.Weight);
Join(root1, root2);
}
}
} int main() {
int totEdge;
scanf("%d%d", &_vCount, &totEdge);
for (int i = 1; i <= totEdge; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
Build(u, v, w);
}
Kruskal();
DfsStart();
int queryCnt;
scanf("%d", &queryCnt);
while (queryCnt--) {
int u, v;
scanf("%d%d", &u, &v);
printf("%d\n", Lca(_nodes + u, _nodes + v));
}
return 0;
}

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. POJ 1236 Tarjan算法

    这道题认真想了想.. [ 题目大意:有N个学校,从每个学校都能从一个单向网络到另外一个学校,两个问题 1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件. 2:至少需要添加几条 ...

  2. F - Micro-World(简单模拟)

    Problem description You have a Petri dish with bacteria and you are preparing to dive into the harsh ...

  3. Kali linux 2016.2(Rolling)之 Nessus安装及Plugins Download Fail 解决方法

    最近,因科研需要,学习Nessus. Nessus是一款优秀的漏洞扫描软件,在其v6 HOME版本中在线更新漏洞插件不成功,采用离线更新,成功地更新了插件,在此将更新方法进行分享. 1.Nessus软 ...

  4. springboot 的一般配置

    import javax.servlet.Filter; import org.springframework.boot.SpringApplication; import org.springfra ...

  5. Asp.net MVC Checkbox控件 和 Nullable<bool>, 或bool?类型

    @Html.CheckBoxFor() 这个方法生成两个Input HTML标签,不明白为什么这样,如果数据库是Nullable<bool>类型,就会报错. 网上的解决方法是这样: 方法一 ...

  6. ie8及其以下版本兼容性问题之圆角

    解决办法:在http://css3pie.com/页面下载一个PIE.htc的文件,加载到根目录下,然后在css中加上一句behavior:url(../js/PIE.htc);如下: .border ...

  7. [WIFI插座][阅读记录][SoC][RT5350] 00.目录 RALINK AP SDK 4.1.0.0 USER’s MANUAL

    来源是CSDN,百度网盘下载地址 http://pan.baidu.com/share/link?shareid=3504767505&uk=3426044377   授权声明,略过 免责声明 ...

  8. 【SQL】ROWNUM和ROWID

    一.ROWNUM ROWNUM伪列是Oracle先查到结果集之后再加上去的一个伪列,这个伪列对符合条件的结果添加一个从1开始的序列号,并且序列号是从1开始增序排列的. SQL> select r ...

  9. 如何修改yii2.0用户登录使用的user表为其它的表

      这只是自己练习的一个记录而已. 因为某种原因,不想用yii自带的user表,想用自己建的admin数据库表,修改如下: 1. 参考高级模板里里的common\models\User 修改 Admi ...

  10. JSP_内置对象_请求转发和请求重定向的区别

    请求重定向:客户端行为,response.sendRedirect(),从本质上将等同与两次请求,前一次请求request对象不会保存,地址栏的URL地址会改变. 请求转发:服务器行为,request ...