【洛谷P4234】最小差值生成树
Description
给定一张n个点,m条边的无向图,求出边权最大值和最小值差值最小的生成树
Solution
LCT+并查集
按照最小生成树的思路,先将边按照边权从小到大排序,然后顺序考虑每一条边
如果当前这条边的两个端点没有连通,那么直接连通
如果两个端点已经连通,我们加上这条边会形成一个环,那么为了让“边权最大值和最小值差值”尽可能小,我们可以将这个环上最短的一条边删掉,换成这条边(显然是对的)
维护最小值可以通过LCT实现,连边、短边也是LCT的基本操作
当目前的边已经是一棵树的时候更新答案即可完成
Code
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 50010; 5 const int M = 200010; 6 inline int read() { 7 int ret = 0, op = 1; 8 char c = getchar(); 9 while (!isdigit(c)) { 10 if (c == '-') op = -1; 11 c = getchar(); 12 } 13 while (isdigit(c)) { 14 ret = (ret << 3) + (ret << 1) + c - '0'; 15 c = getchar(); 16 } 17 return ret * op; 18 } 19 struct Edge { 20 int from, to, dis; 21 bool operator <(const Edge &x) const { 22 return dis < x.dis; 23 } 24 } edge[M]; 25 struct LCT { 26 int fa, val, minn, ch[2], tag; 27 } a[N + M]; 28 int n, m, s[N + M], f[N]; 29 int vis[M]; 30 int find(int x) { 31 if (f[x] != x) return f[x] = find(f[x]); 32 return f[x]; 33 } 34 inline int isnroot(int now) { 35 return a[a[now].fa].ch[0] == now || a[a[now].fa].ch[1] == now; 36 } 37 inline int get(int x, int y) { 38 return a[x].val < a[y].val ? x : y; 39 } 40 inline void update(int now) { 41 int l = a[now].ch[0]; 42 int r = a[now].ch[1]; 43 a[now].minn = get(now, get(a[l].minn, a[r].minn)); 44 } 45 inline void rev(int now) { 46 swap(a[now].ch[0], a[now].ch[1]); 47 a[now].tag ^= 1; 48 } 49 inline void pushdown(int now) { 50 if (a[now].tag) { 51 if (a[now].ch[0]) rev(a[now].ch[0]); 52 if (a[now].ch[1]) rev(a[now].ch[1]); 53 a[now].tag = 0; 54 } 55 } 56 void rotate(int x) { 57 int y = a[x].fa; 58 int z = a[y].fa; 59 int xson = a[y].ch[1] == x; 60 int yson = a[z].ch[1] == y; 61 int B = a[x].ch[xson ^ 1]; 62 if (isnroot(y)) a[z].ch[yson] = x; 63 a[x].ch[xson ^ 1] = y; 64 a[y].ch[xson] = B; 65 if (B) a[B].fa = y; 66 a[y].fa = x; 67 a[x].fa = z; 68 update(y); 69 } 70 void splay(int x) { 71 int y = x, z = 0; 72 s[++z] = y; 73 while (isnroot(y)) y = a[y].fa, s[++z] = y; 74 while (z) pushdown(s[z--]); 75 while (isnroot(x)) { 76 y = a[x].fa; 77 z = a[y].fa; 78 if (isnroot(y)) 79 (a[z].ch[0] == y) ^ (a[y].ch[0] == x) ? rotate(x) : rotate(y); 80 rotate(x); 81 } 82 update(x); 83 } 84 void access(int x) { 85 for (register int y = 0; x; y = x, x = a[x].fa) { 86 splay(x); a[x].ch[1] = y; update(x); 87 } 88 } 89 void makeroot(int x) { 90 access(x); 91 splay(x); 92 rev(x); 93 } 94 void link(int i) { 95 makeroot(edge[i].from); 96 a[edge[i].from].fa = i + N; 97 a[i + N].fa = edge[i].to; 98 } 99 void cut(int i) { 100 access(edge[i - N].from); 101 splay(i); 102 a[a[i].ch[1]].fa = a[a[i].ch[0]].fa = 0; 103 a[i].ch[0] = a[i].ch[1] = 0; 104 } 105 int main() { 106 n = read(); m = read(); 107 for (register int i = 0; i <= n; ++i) f[i] = i, a[i].val = 2147483647; 108 for (register int i = 1; i <= m; ++i) { 109 edge[i].from = read(); edge[i].to = read(); edge[i].dis = read(); 110 } 111 sort(edge + 1, edge + m + 1); 112 int sum = 0, ans = 0, k = 1; 113 for (register int i = 1; i <= m; ++i) { 114 a[i + N].val = edge[i].dis; 115 int x = edge[i].from; 116 int y = edge[i].to; 117 if (find(x) != find(y)) { 118 vis[i] = 1; 119 sum++; 120 link(i); 121 f[f[x]] = f[y]; 122 if (sum == n - 1) ans = edge[i].dis - edge[k].dis; 123 } 124 else { 125 if (x == y) continue ; 126 vis[i] = 1; 127 makeroot(x); 128 access(y); splay(y); 129 vis[a[y].minn - N] = 0; 130 while (vis[k] == 0) ++k; 131 cut(a[y].minn); link(i); 132 if (sum == n - 1) ans = min(ans, edge[i].dis - edge[k].dis); 133 } 134 } 135 printf("%d\n", ans); 136 return 0; 137 }
AC Code
转载于:https://www.cnblogs.com/shl-blog/p/11354557.html
【洛谷P4234】最小差值生成树相关推荐
- [洛谷P4234]最小差值生成树
给定一个标号为从$1$到$n$的.有$m$条边的无向图,求边权最大值与最小值的差值最小的生成树. 做法类似魔法森林,首先求出来最小生成树,然后每次加入一条边,断掉环上最小边并更新答案 这个过程我用两个 ...
- 洛谷.4234.最小差值生成树(LCT)
题目链接 先将边排序,这样就可以按从小到大的顺序维护生成树,枚举到一条未连通的边就连上,已连通则(用当前更大的)替换掉路径上最小的边,这样一定不会更差. 每次构成树时更新答案.答案就是当前边减去生成树 ...
- 洛谷P5633 最小度限制生成树 题解
洛谷P5633 最小度限制生成树 题解 题目链接:P5633 最小度限制生成树 题意: 给你一个有 n n n 个节点, m m m 条边的带权无向图,你需要求得一个生成树,使边权总和最小,且满足编号 ...
- 洛谷 1351 联合权值
[题解] 每个点维护各个儿子的前后缀最大值.权值和,这样就可以统计儿子之间相乘的答案.然后每个节点再乘它的祖父的权值去更新答案即可. 1 #include<cstdio> 2 #inclu ...
- 洛谷P1351 联合权值(树形dp)
题意 题目链接 Sol 一道很简单的树形dp,然而被我写的这么长 分别记录下距离为\(1/2\)的点数,权值和,最大值.以及相邻儿子之间的贡献. 树形dp一波.. #include<bits/s ...
- 洛谷 1351 联合权值——树形dp
题目:https://www.luogu.org/problemnew/show/P1351 对拍了一下,才发现自己漏掉了那种拐弯的情况. #include<iostream> #incl ...
- 信息学奥赛一本通 1956:【11NOIP普及组】表达式的值 | 洛谷 P1310 [NOIP2011 普及组] 表达式的值
[题目链接] ybt 1956:[11NOIP普及组]表达式的值 洛谷 P1310 [NOIP2011 普及组] 表达式的值 [题目考点] 表达式树 由带括号的中缀表达式构建表达式树 [解题思路] 思 ...
- 信息学奥赛一本通 1962:【13NOIP普及组】表达式求值 | 洛谷 P1981 [NOIP2013 普及组] 表达式求值
[题目链接] ybt 1962:[13NOIP普及组]表达式求值 洛谷 P1981 [NOIP2013 普及组] 表达式求值 [题目考点] 栈 中缀表达式转后缀表达式,后缀表达式求值 中缀表达式求值 ...
- 【杂题总汇】NOIP2013(洛谷P1967) 货车运输
[洛谷P1967] 货车运输 重做NOIP提高组ing... +传送门-洛谷P1967+ ◇ 题目(copy from 洛谷) 题目描述 A国有n座城市,编号从1到n,城市之间有m条双向道路.每一条道 ...
- 信息学奥赛一本通 1392:繁忙的都市(city) | 洛谷 P2330 [SCOI2005]繁忙的都市
[题目链接] ybt 1392:繁忙的都市(city) 洛谷 P2330 [SCOI2005]繁忙的都市 [题目考点] 1. 图论 最小生成树 [解题思路] 将题目叙述转为图论概念,交叉路口为顶点,道 ...
最新文章
- LeetCode 滑动窗口(Sliding Window)类问题总结
- [译] MDC-101 Flutter:Material Components(MDC)基础(Flutter)
- DYNP_VALUES_READ
- 笔记-高项案例题-2015年上-计算题
- C++ cin cout
- 远控免杀专题(15)-DKMC免杀
- MySQL not in查询不出数据(MySQL not in 无效)
- 用c语言写出一个榜单程序,C语言依然位居榜单前列,依然值得程序员学习
- bzoj4569 [Scoi2016]萌萌哒 并查集+st表
- buck变换器设计matlab_[Fundamental of Power Electronics]-PART I-6.变换器电路-6.2 变换器简单罗列 - Yangswear...
- oracle 赋予dorp,oracle表空间(tablespace)的增删改查(create/drop/rename,move/select)
- Python天天美味(4) - isinstance判断对象类型
- Linux下autoconf与automake
- C++ 之父即将开始直播,请就位!
- 设计模式—结构型模式概述(思维导图)
- 《vSphere性能设计:性能密集场景下CPU、内存、存储及网络的最佳设计实践》一1.2.4 存储...
- Python使用requests发送post请求
- 小米笔记本系统win10家庭版升级为企业版(专业版)
- 关于三方支付做的一个小总结,后期不断完善更新
- 43-圣诞老人的礼物
热门文章
- 虚拟机中试用windows 8(视频)
- 图论1:哥尼斯堡七桥问题的证明
- 玛雅历 —— C++
- 中国诺贝尔物理学奖所有获得者名单(转)
- 计算机英语解读,解释计算机Windows的学习英语
- “您未被授权查看该页,您不具备使用所提供的凭据查看该目录或页的权限” -- 解决办法
- Windows系统封装步骤
- [Java学习] 小型社交平台,能发帖、查看、评论、删除帖子等功能
- 【转载】电磁波中的波段划分:L波段、S波段、C波段、X波段、Ku波段、K波段、Ka波段 等等
- opencv学习笔记(一) 环境配置/打开一张图片/github(git)初探