luogu题目传送门!

首先,题目让我们求每个货车的最大运输量,翻译一下就是求路径上边权最小的边。

利用一下贪心思想可知,所有货车肯定都会尽量往大的边走。

进一步翻译,即为有一些小边货车根本不会走,或者说,我们只用知道点与点之间最大的连通路径就好了。

!!!

那么,我们求一下最大生成树,就可以知道最大连通图了。

然后来到第二步:求出了最大生成树,即树上点与点的路径只有一条,这条路也肯定是符合题目要求的。

那么,如何求出路径上最小的边?
暴力DFS?FLOYD?SPFA?

最快也是O(N*P)的复杂度让你通通T掉!

因此,面对如此多的询问,考虑在线维护的做法,不考虑问一次遍历一次的做法。

于是,众神仙便想出了倍增的做法:

在倍增的时候维护一个w, 和倍增的f类似, w应该存储指向w方向的最小边。

每次询问时,快速倍增取min就好了。

#include <bits/stdc++.h>
using namespace std;
#define N 500010
#define INF (~0u>>1) inline int read(){
int x = , s = ;
char c = getchar();
while(!isdigit(c)){
if(c == '-')s = -;
c = getchar();
}
while(isdigit(c)){
x = (x << ) + (x << ) + (c ^ '');
c = getchar();
}
return x * s;
} struct edge{ // 临时存边
int u, v, dis;
} e[N]; struct node{
int u, v, w;
int next;
} t[N];
int head[N];
int fa[N]; // 并查集
int n, m; int bian = ;
inline void add(int u, int v, int w){
t[++bian].u = u;
t[bian].v = v;
t[bian].w = w;
t[bian].next = head[u];
head[u] = bian;
return ;
} bool cmp(edge a, edge b){
return a.dis > b.dis;
} inline int find(int x){
if(x == fa[x])return fa[x];
else return fa[x] = find(fa[x]);
} inline void kruskal(int n, int m){ // 求最大生成树
sort(e + , e + m + , cmp);
for(int i = ;i <= n; i++)
fa[i] = i; // 并查集初始化
for(int i = ;i <= m; i++){
int fau = find(e[i].u), fav = find(e[i].v);
int u = e[i].u, v = e[i].v;
if(fau != fav){
fa[fau] = fav;
add(u, v, e[i].dis);
add(v, u, e[i].dis);
}
}
return ;
} namespace LCA{
int deth[N], f[N][];
int w[N][];
bool vis[N]; void dfs(int now){
vis[now] = ;
for(int i = head[now]; i; i = t[i].next){
int v = t[i].v, u = t[i].u,dis = t[i].w;
if(!vis[v]){
deth[v] = deth[now] + ;
w[v][] = dis; // w 储存指向v的边权, 在 LCA 初始化时应变成 LCA 路径上的最小值
f[v][] = now; // f0 即为自己的上一个
dfs(v);
}
}
return ;
} int lca(int x, int y){
if(find(x) != find(y))return -; // 两个点不连通
int ans = INF;
if(deth[x] > deth[y])swap(x, y);
for(int i = ; i >= ;i--){
if(deth[f[y][i]] >= deth[x]){
ans = min(ans, w[y][i]);
y = f[y][i]; // 先拉近距离
}
}
if(x == y)return ans;
for(int i = ;i >= ; i--){//优先跳大的
if(f[x][i] != f[y][i]){
ans = min(ans, min(w[x][i], w[y][i])); // 更新
x = f[x][i];
y = f[y][i];//上跳
}
}
ans = min(ans, min(w[x][], w[y][])); // 更新
return ans;
} void main(){
for(int i = ;i <= n;i++){ // 恶心数据可能不连通
if(!vis[i]){
deth[i] = ;
dfs(i);//第一次储存信息
w[i][] = INF;// 开头,不可能有 w
f[i][] = i;// 开头,本不配有 f。 因此存成自己
}
}
for(int i = ;i <= ; i++){
for(int j = ;j <= n; j++){
f[j][i] = f[f[j][i-]][i-];
w[j][i] = min(w[j][i-], w[f[j][i-]][i-]);//LCA初始化, w应保存 LCA路上指向j点方向的最小边
}
}
int q = read();
for(int i = ;i <= q; i++){
int x = read(), y = read();
printf("%d\n", lca(x, y));
}
return ;
} } int main(){
n = read(), m = read();
for(int i = ;i <= m; i++){
int x = read(), y = read(), z = read();
e[i].u = x;
e[i].v = y;
e[i].dis = z;//第一次存储
}
kruskal(n, m);//求最大生成树
LCA::main();
return ;
}

货车运输 noip2013 luogu P1967 (最大生成树+倍增LCA)的更多相关文章

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

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

  2. TZOJ 4848 货车运输(最大生成树+倍增lca)

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

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

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

  4. 【洛谷1967】货车运输(最大生成树+倍增LCA)

    点此看题面 大致题意: 有\(n\)个城市和\(m\)条道路,每条道路有一个限重.多组询问,每次询问从\(x\)到\(y\)的最大载重为多少. 一个贪心的想法 首先,让我们来贪心一波. 由于要求最大载 ...

  5. Codevs 3287 货车运输 == 洛谷P1967

    3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description A 国有 n 座城市,编 ...

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

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

  7. 洛谷P1967 货车运输 [noip2013] 图论

    正解:kruskal+LCA 解题报告: 哇真实心痛了...明明都没多少时间了我居然耗了一个上午+一个中午在上面?哭死辽我QAQ果然菜是原罪QAQ 然后这题,我先港下60pts做法趴?话说其实我觉得我 ...

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

    传送门 这道题,先用kruskal求一遍图中的最大生成树. 然后,倍增求lca,求lca的同时求出边权的最小值. #include <cstring> #include <cstdi ...

  9. 货车运输-洛谷-1967-LCA+最大生成树(kruskal(并查集))

    传送门 一道:LCA+最大生成树 个人认为把这两个的板子写好(并熟练掌握了之后)就没什么难的 (但我还是de了好久bug)qwq 最大生成树:其实就是最小生成树的变形 我用的是kruskal (个人觉 ...

随机推荐

  1. 0x01-Linux常用文件处理命令

    0x01-Linux常用文件处理命令 摘要 文件可以说是占据了Linux系统半壁江山,那么,我们理所应当要认识文件,且还要懂得如何创建.查看文件(touch.cat命令).既然是使用Linux,当然是 ...

  2. GitHub 热点速览 Vol.18:刷 LeetCode 的正确姿势

    作者:HelloGitHub-小鱼干 摘要:找对路子,事半功倍,正如本周 GitHub Trending #刷 LeetCode# 主题想表达的那般,正确的学习姿势方能让人走得更远,走进大厂

  3. turtle库应用实例-五角星绘制

    五角星绘制 ‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬ ...

  4. P2309(逆序对)

    传送门 描述:给定一个序列长n,求多少子串和大于零. \(一开始一定会想到根据前缀和优化,枚举起点和中点O(n)解决\) \(那更高效的方法呢?实际上,我们上面就是要求S_i-S_j>0的数量\ ...

  5. Educational Codeforces Round 77 (Rated for Div. 2) C. Infinite Fence

    C. Infinite Fence 题目大意:给板子涂色,首先板子是顺序的,然后可以涂两种颜色,如果是r的倍数涂成红色,是b的倍数涂成蓝色, 连续的k个相同的颜色则不能完成任务,能完成任务则输出OBE ...

  6. Course Selection System ZOJ - 3956 01背包+思维

    Course Selection System ZOJ - 3956 这个题目居然是一个01背包,我觉得好难想啊,根本就没有想到. 这个题目把题目给的转化为  ans = a*a-a*b-b*b 这个 ...

  7. P2765 魔术球问题 网络流二十四题重温

    P2765 魔术球问题 知识点::最小点覆盖 这个题目要拆点,这个不是因为每一个球只能用一次,而是因为我们要求最小点覆盖,所以要拆点来写. 思路: 首先拆点,然后就是开始建边,因为建边的条件是要求他们 ...

  8. Android广播时间——实现强制下线功能

    目录 思路:强制下线功能需要先关闭掉所有的活动,然后回到登录界面. 步骤 1.关闭所有活动 2.创建BaseActivity类作为所有活动的父类,因为需要用ActivityCollector管理所有活 ...

  9. [hdu5256]LIS模型

    题目:有一个数列A1,A2...An,修改数量最少的元素,使得这个数列严格递增.无论是修改前还是修改后,每个元素都必须是整数. 思路: 修改数量最少的元素使得这个数列严格递增,等价于让数量最多的元素不 ...

  10. netty零基础入门

    直接上代码,从最基本的接收消息规则开始 package cn.qdl; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelH ...