给定一个标号为从$1$到$n$的、有$m$条边的无向图,求边权最大值与最小值的差值最小的生成树。

做法类似魔法森林,首先求出来最小生成树,然后每次加入一条边,断掉环上最小边并更新答案

这个过程我用两个堆维护的

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 #define M 500010
  7 #define ls ch[x][0]
  8 #define rs ch[x][1]
  9 using namespace std;
 10 int n,m,ans,top,cnt;
 11 int st[M],f[M],fa[M],rev[M],minn[M],val[M],id[M],ch[M][2];
 12 struct node{int v;};
 13 priority_queue<node>q1,q2;
 14 bool operator < (node a1,node a2) {
 15     return a1.v>a2.v;
 16 }
 17 void heap_pop(int v) {
 18     q1.push((node){v});
 19 }
 20 void heap_push(int v) {
 21     q2.push((node){v});
 22 }
 23 int heap_top() {
 24     while(!q1.empty()) {
 25         int x1=q1.top().v,x2=q2.top().v;
 26         if(x1==x2) q1.pop(),q2.pop();
 27         else break;
 28     }
 29     return q2.top().v;
 30 }
 31 struct point{
 32     int u,v,w;
 33 }a[M];
 34 bool cmp(point a1,point a2) {
 35     return a1.w<a2.w;
 36 }
 37 int find(int x) {
 38     return fa[x]==x?x:fa[x]=find(fa[x]);
 39 }
 40 void update(int x) {
 41     minn[x]=val[x];id[x]=x;
 42     if(ls&&minn[ls]<minn[x]) minn[x]=minn[ls],id[x]=id[ls];
 43     if(rs&&minn[rs]<minn[x]) minn[x]=minn[rs],id[x]=id[rs];
 44 }
 45 void pushdown(int x) {
 46     if(rev[x]) {
 47         if(ls) rev[ls]^=1;
 48         if(rs) rev[rs]^=1;
 49         swap(ls,rs),rev[x]^=1;
 50     }
 51 }
 52 int get(int x) {
 53     return ch[f[x]][1]==x;
 54 }
 55 bool is_root(int x) {
 56     return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;
 57 }
 58 void rotate(int x) {
 59     int old=f[x],oldf=f[old],k=get(x);
 60     if(!is_root(old)) ch[oldf][ch[oldf][1]==old]=x;
 61     ch[old][k]=ch[x][k^1],f[ch[old][k]]=old;
 62     ch[x][k^1]=old,f[old]=x,f[x]=oldf;
 63     update(old),update(x);
 64 }
 65 void splay(int x) {
 66     st[top=1]=x;
 67     for(int i=x;!is_root(i);i=f[i]) st[++top]=f[i];
 68     for(int i=top;i>=1;i--) pushdown(st[i]);
 69     for(int fa;!is_root(x);rotate(x))
 70         if(!is_root(fa=f[x]))
 71             rotate(get(x)==get(fa)?fa:x);
 72 }
 73 void access(int x) {
 74     for(int y=0;x;y=x,x=f[x])
 75         splay(x),ch[x][1]=y,update(x);
 76 }
 77 void makeroot(int x) {
 78     access(x);splay(x);rev[x]^=1;
 79 }
 80 void spilt(int x,int y) {
 81     makeroot(x);access(y);splay(y);
 82 }
 83 void link(int x,int y) {
 84     makeroot(x);f[x]=y;splay(x);
 85 }
 86 void cut(int x,int y) {
 87     spilt(x,y);f[x]=ch[y][0]=0;
 88 }
 89 int query(int x,int y) {
 90     spilt(x,y);return id[y];
 91 }
 92 int main() {
 93     scanf("%d%d",&n,&m);
 94     for(int i=1;i<=m;i++)
 95         scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
 96     sort(a+1,a+1+m,cmp);
 97     memset(minn,63,sizeof(minn));
 98     memset(val,63,sizeof(val));
 99     memset(&ans,0x7f,sizeof(ans));
100     for(int i=1;i<=n;i++) fa[i]=i;
101     for(int i=1;i<=m;i++) id[i+n]=i+n,val[i+n]=a[i].w;
102     for(int i=1;i<=m;i++) {
103         int x=a[i].u,y=a[i].v;
104         if(find(x)==find(y)) {
105             int ID=query(x,y);
106             cut(a[ID-n].u,ID),cut(a[ID-n].v,ID);
107             link(x,i+n),link(y,i+n);
108             heap_pop(val[ID]);
109             heap_push(val[i+n]);
110         }
111         else {
112             fa[find(x)]=find(y);
113             link(x,i+n),link(y,i+n);
114             heap_push(val[i+n]);
115             cnt++;
116         }
117         if(cnt==n-1) {
118             ans=min(ans,a[i].w-heap_top());
119         }
120     }
121     printf("%d\n",ans);
122     return 0;
123 }

转载于:https://www.cnblogs.com/Slrslr/p/10022180.html

[洛谷P4234]最小差值生成树相关推荐

  1. 洛谷.4234.最小差值生成树(LCT)

    题目链接 先将边排序,这样就可以按从小到大的顺序维护生成树,枚举到一条未连通的边就连上,已连通则(用当前更大的)替换掉路径上最小的边,这样一定不会更差. 每次构成树时更新答案.答案就是当前边减去生成树 ...

  2. 洛谷P5633 最小度限制生成树 题解

    洛谷P5633 最小度限制生成树 题解 题目链接:P5633 最小度限制生成树 题意: 给你一个有 n n n 个节点, m m m 条边的带权无向图,你需要求得一个生成树,使边权总和最小,且满足编号 ...

  3. 洛谷 1351 联合权值

    [题解] 每个点维护各个儿子的前后缀最大值.权值和,这样就可以统计儿子之间相乘的答案.然后每个节点再乘它的祖父的权值去更新答案即可. 1 #include<cstdio> 2 #inclu ...

  4. 洛谷P1351 联合权值(树形dp)

    题意 题目链接 Sol 一道很简单的树形dp,然而被我写的这么长 分别记录下距离为\(1/2\)的点数,权值和,最大值.以及相邻儿子之间的贡献. 树形dp一波.. #include<bits/s ...

  5. 洛谷 1351 联合权值——树形dp

    题目:https://www.luogu.org/problemnew/show/P1351 对拍了一下,才发现自己漏掉了那种拐弯的情况. #include<iostream> #incl ...

  6. 信息学奥赛一本通 1956:【11NOIP普及组】表达式的值 | 洛谷 P1310 [NOIP2011 普及组] 表达式的值

    [题目链接] ybt 1956:[11NOIP普及组]表达式的值 洛谷 P1310 [NOIP2011 普及组] 表达式的值 [题目考点] 表达式树 由带括号的中缀表达式构建表达式树 [解题思路] 思 ...

  7. 信息学奥赛一本通 1962:【13NOIP普及组】表达式求值 | 洛谷 P1981 [NOIP2013 普及组] 表达式求值

    [题目链接] ybt 1962:[13NOIP普及组]表达式求值 洛谷 P1981 [NOIP2013 普及组] 表达式求值 [题目考点] 栈 中缀表达式转后缀表达式,后缀表达式求值 中缀表达式求值 ...

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

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

  9. 信息学奥赛一本通 1392:繁忙的都市(city) | 洛谷 P2330 [SCOI2005]繁忙的都市

    [题目链接] ybt 1392:繁忙的都市(city) 洛谷 P2330 [SCOI2005]繁忙的都市 [题目考点] 1. 图论 最小生成树 [解题思路] 将题目叙述转为图论概念,交叉路口为顶点,道 ...

最新文章

  1. 三代测序之微生物基因组 de novo 测序
  2. poj 2411 Mondriaan#39;s Dream 【dp】
  3. 挖掘 OSINT 金矿——实习生和社交媒体
  4. Eclipse自动生成返回值对象与补全与加注释
  5. vue data变量之间相互赋值或进行数据联动
  6. Lintcode14 First Position of Target Solution 题解
  7. java http get 图片_http协议get方法获取图片并保存到本地
  8. 【免费分享】收集整理的117套各类微信小程序模板源码分享
  9. java合并2个txt文本,Java实现多个文档合并输出到一个文档
  10. 谈MDM主数据管理系统、BI、大数据、SOA之间的关系
  11. 推荐几个好用又好玩的vscode插件!
  12. android als传感器,环境光传感器(ALS)背光控制系统解决方案
  13. guava-retry介绍
  14. java课程设计 雍俊海_java课程设计模拟科学计算器【参考】.doc
  15. 汇编语言-用Si和Di实现字符串复制到其他的区域
  16. 终于学会数组的使用啦~~~------C语言数组学习笔记详解
  17. POI实现 Excel插入图片
  18. Lucene学习——IKAnalyzer中文分词(一)
  19. 计算机工程学院文艺例会,信息科学与工程学院学生会学生会全体例会暨部门风采展示大会...
  20. 干货|chrome浏览器模拟定位

热门文章

  1. java基础的知识_Java基础知识点(一)
  2. JSch连接不上Linux服务器,windows 下 java程序jsch连接远程linux服务器执行shell命令
  3. 爬虫教程 python3_Python3网络爬虫(四): 登录
  4. 日志记录到字段变更_Wal日志解析工具开源: Walminer
  5. cad2008加载 et拓展工具_译文:8个值得推荐的用于前端开发的性能分析工具「渡一教育」...
  6. Apollo开发平台授权管理的使用
  7. Linux中locate命令查找文件位置
  8. C++ 构造函数与析构函数
  9. RSA大会:中国信息安全的“走出去”与“学回来”
  10. 译 | 像使用一台主机一样管理集群