传送门

其实NOIP某些年的第三题也并不是很难嘛。。。

题目分析:

  • 题目中要求求出某两点之间可以运输的最大重量,也就是这两个点的某条路径上边权最小的边的权值的最大值
  • 很显然,题目中的运输最大重量与选择的边数,走法,无关边的权值均无关,可以求出这张图的最大生成树,在树上进行询问,与图中询问结果相同
  • 由于该图不保证连通性,所以实际形成的是一个最大生成森林,那么对于每个询问,直接用并查集判断是否存在,对于存在的询问,考虑优化查询的时间
  • 既然已经把图压缩成了森林,那么就可以使用一些树特有的性质了,,对于树上两个点,求他们之间的边的最小值,,,可以考虑使用倍增了,维护jump数组的基础上,维护low数组,使用low[x][0]low[x][0]表示以x的父亲边的权值,low[x][i]low[x][i]表示x到x的2i2^i代父亲的权值最小值,那么题目中的查询就可以转化为两个点到他们LCA的路径上的最小值,每次倍增寻找结果输出即可

题解:

  • 对原图进行kruskal求最大生成树,在其过程中用邻接表把选择的边建好
  • dfs求出倍增中的dis数组,jump[x][0],low[x][0]
  • 枚举i,j更新jump数组和low数组,jump[x][j]=jump[jump[x][j−1]][j−1]jump[x][j] = jump[jump[x][j-1]][j-1] low[x][i]=min(low[x][i−1],low[jump[x][i−1]][i−1])low[x][i] = min(low[x][i-1], low[jump[x][i-1]][i-1])
  • 常规倍增求LCA,设ans初始值为INF,每次与当前的low值取min,输出ans即为结果

Warning:

  • 倍增LCA的j为外层循环!!!
  • 倍增LCA的j为外层循环!!!
  • 倍增LCA的j为外层循环!!!
  • 倍增LCA的j为外层循环!!!
  • 倍增LCA的j为外层循环!!!

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
//#define debug
const int inf = 0x3f3f3f3f;
const int maxn = 20000;
const int maxm = 100000 + 500;
struct edge{int from;int to;int val;
};
edge p[maxm];
int n, m;
int father[maxn];
int last[maxn], pre[maxm], other[maxm], len[maxm];
int jump[maxn][25];
int dis[maxn];
int low[maxn][25];
int tot = 0;
int x, y;
void add(int x, int y, int z) {tot++;pre[tot] = last[x];last[x] = tot;other[tot] = y;len[tot] = z;
}
int getfather(int x) {if (father[x] == x) return (x);return (father[x] = getfather(father[x]));
}bool cmp(edge aa, edge bb) {return (aa.val > bb.val);
}void dfs(int x, int come, int comep) {jump[x][0] = come;low[x][0] = comep;dis[x] = dis[come] + 1;for (int p = last[x]; p; p = pre[p]) {int q = other[p];if (q == come) continue;dfs(q, x, len[p]);}
}int main () {//freopen("truck.in", "r", stdin);//freopen("truck.out", "w", stdout);scanf("%d %d", &n, &m);memset(low, 127, sizeof(low));for (int i = 1; i <= m; i++) {scanf("%d %d %d", &p[i].from, &p[i].to, &p[i].val);}for (int i = 1; i <= n; i++) father[i] = i;std :: sort(p + 1, p + m + 1, cmp);for (int i = 1; i <= m; i++) {int tx = getfather(p[i].from);int ty = getfather(p[i].to);if (tx == ty) continue;father[tx] = ty;add(p[i].from, p[i].to, p[i].val);add(p[i].to, p[i].from, p[i].val);}for (int i = 1; i <= n; i++) {if (dis[i] == 0) {dfs(i, 0, inf);}}for (int j = 1; j <= 20; j++) {for (int i = 1; i <= n; i++) {jump[i][j] = jump[jump[i][j-1]][j-1];low[i][j] = std :: min(low[i][j-1], low[jump[i][j-1]][j-1]); }}
#ifdef debugfor (int i = 1; i <= n; i++) {printf("low[%d] = %d\n", i, low[i][0]);}//exit(0);
#endifint q;scanf("%d", &q);while (q--) {scanf("%d %d", &x, &y);int tx = getfather(x);int ty = getfather(y);if (tx != ty) {printf("-1\n");continue;}int ans = inf;if (dis[x] != dis[y]) {if (dis[x] < dis[y]) std :: swap(x, y);for (int j = 20; j >= 0; j--) {if (dis[jump[x][j]] > dis[y]) {ans = std :: min(ans, low[x][j]);x = jump[x][j];}}ans = std :: min(ans, low[x][0]);x = jump[x][0];} for (int j = 20; j >= 0; j--) {if (jump[x][j] != jump[y][j]) {ans = std :: min(ans, low[x][j]);ans = std :: min(ans, low[y][j]);x = jump[x][j];y = jump[y][j];}}if (x != y) {ans = std :: min(low[x][0], ans);ans = std :: min(low[y][0], ans);}printf("%d\n", ans);}return 0;
}

洛谷1967 火车运输 kruskal求最大生成树 倍增LCA维护最小值相关推荐

  1. 洛谷1967 火车运输

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

  2. 洛谷T1967 货车运输 Kruskal最大生成树倍增LCA

    这题的题意是:对于每组x.y,求x到y路径上最小边权的最大值. 于是可以使用最大生成树,因为最大生成树满足性质:生成树中最小边权最大,且任意两点间路径上最小边权最大. 有了树之后,要求路径,那就要考虑 ...

  3. 洛谷1967货车运输

    题目:https://www.luogu.org/problemnew/show/P1967 倍增LCA裸题.用了在线.还有离线O(n)做法.树链剖分做法,暂不管了. (自己程序的)坑点:1.xnt从 ...

  4. 洛谷 - P4768 [NOI2018]归程(Kruskal重构树+树上倍增+最短路)

    题目链接:点击查看 题目大意:去原网址看吧 题目分析:因为是在刷克鲁斯卡尔重构树的题目,所以稍微思考一下就能想出解法了,首先如果水位线固定了,剩下的边组成的最小生成树也是一定的,此时同一个连通块内的点 ...

  5. 洛谷P3379 【模板】最近公共祖先(LCA)

    洛谷P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数 ...

  6. 【杂题总汇】NOIP2013(洛谷P1967) 货车运输

    [洛谷P1967] 货车运输 重做NOIP提高组ing... +传送门-洛谷P1967+ ◇ 题目(copy from 洛谷) 题目描述 A国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道 ...

  7. noip 2013 洛谷 P1967 货车运输

    题目:货车运输 大致题意: 给出一张无向带权图,对于m个询问(X,Y),要求找出X到Y的一条路径使得路径上的最小边权最大,并输出这个最小边权. 思路: 可以看出,X到Y的满足条件的路径一定在原图的最大 ...

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

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

  9. 洛谷P4768 [NOI2018]归程(Kruskal重构树)

    题意 直接看题目吧,不好描述 Sol 考虑暴力做法 首先预处理出从$1$到每个节点的最短路, 对于每次询问,暴力的从这个点BFS,从能走到的点里面取$min$ 考虑如何优化,这里要用到Kruskal重 ...

最新文章

  1. 非常适合小白的 Asyncio 教程
  2. 一起来做个免登录资源导航小程序!
  3. 深入理解Magento – 第六章 – 高级Magento模型
  4. jdk的ServiceLoader
  5. OO ALV 实现方式 ALV TABLE 之 栏位属性
  6. 数学模型——Logistic回归模型(含Matlab代码)
  7. php三极管导通条件,三极管的导通条件 - 三级管饱和导通的条件是什么?
  8. 匹配区县代码_省份、城市、区县三级联动Html代码
  9. JAVA计算机毕业设计网上图书销售系统(附源码、数据库)
  10. 数字化到底有什么用?
  11. Kaggle文本语义相似度计算Top5解决方案分享
  12. 匈奴国王阿提拉:令整个欧洲发抖的上帝之鞭
  13. JSP设置Excel表格换行_工作中常见的11个Excel难题,一次解决!
  14. Photoshop CS6 for Mac破解版/序列号简介
  15. 油库、加油站、危化企业防雷工程应用方案
  16. 结对编程 王坤彬 201421123108
  17. 16位字长的计算机,十六位字长的计算机是指计算机16位十进制数的计算机吗
  18. 9.条件语句(if语句)
  19. 【IOS】自己写的一个舒尔特方格app
  20. 该怎么职场中进行有效沟通工作?

热门文章

  1. 身为土木牛马的我是如何成功提桶拿到互联网前端50w大厂offer的
  2. 牛人经验:看美剧学习英语的诀窍
  3. 嵌入式开发人员,这些SRAM、SDRAM等存储技术,需要了解一下
  4. c语言用库函数求正弦数,用C语言求正弦值?
  5. 中国移动飞信免费发短信API接口(第三方)
  6. kafka消费者--coordinate分析
  7. JAVA生成二维码(一)
  8. C++各种数据类型所占内存大小
  9. 如何积累财富[转载] 我觉得挺经典 和大家一起分享一下!
  10. PC用PSV游戏下载工具NPS_Browser+本地缓存文件