当前位置: 首页 > news >正文

qoj4239 MST

题意

给出 \(n\) 个整数 \(a_i\)。有一个 \(n\) 个点的无向完全图,定义 \(x,y\pod {x<y}\) 的边权为 \(a_y-a_x\),问这个图的最小生成树。

思路

完全图最小生成树,考虑 Boruvka 最小生成树算法。

具体的说,初始状态为 \(n\) 个单独的点,因此有 \(n\) 个连通块。

每次对每个连通块找到连接到另一个连通块的最小边权,全部找完后进行连接,若要连接的两个原连通块不在同一连通块中则连接。

随后递归进行以上操作,即可求出最小生成树。

由于每次规模缩小一半,所以复杂度是 \(O(n\log n)\) 的,前提是能快速找到连接另一连通块的最小边权。

对于 \(a_i\),显然在它的左边的最大 \(a_i\) 和在它右边的最小 \(a_i\) 可能成为连接它的最小边权。

于是我们对 \(i\) 维护在 \(i\) 左边的最大 \(a_i\) 和右边的最小 \(a_i\)且不在同一连通块中

可以用一个 set 存下每个连通块的最大最小值,若要求的最大最小值为该连通块,则后移一位即可。

代码

💩💩💩💩💩💩💩

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define inf 0x3f3f3f3f3f3f3f3f
int T,n,a[300005],f[300005],f2[300005],mx1[300005],mn1[300005],mnm[300005],mni[300005];
set<pair<int,int>> imx,imn;//最大值,连通块
int lmx[300005],lmn[300005];
int find(int x){if(f[x]!=x) f[x]=find(f[x]);return f[x];
}
int find2(int x){if(f2[x]!=x) f2[x]=find2(f2[x]);return f2[x];
}
int boruvka(){//1 8for(int i=1;i<=n;i++)f[i]=i,f2[i]=i;int cnt=n,res=0;while(cnt!=1){imx.clear();for(int i=1;i<=n;i++)mnm[i]=inf,mni[i]=0,lmx[i]=0,mx1[i]=0,imx.insert({-inf,find(i)});a[0]=-inf;for(int i=1;i<=n;i++){mx1[i]=lmx[prev(imx.end())->second];if(find(mx1[i])==find(i)){if(imx.size()>1)mx1[i]=lmx[prev(prev(imx.end()))->second];elsemx1[i]=0;}imx.erase({a[lmx[find(i)]],find(i)});if(a[i]>a[lmx[find(i)]])lmx[find(i)]=i;imx.insert({a[lmx[find(i)]],find(i)});}imn.clear();for(int i=1;i<=n;i++)lmn[i]=0,mn1[i]=0,imn.insert({inf,find(i)});a[0]=inf;for(int i=n;i>=1;i--){mn1[i]=lmn[imn.begin()->second];if(find(mn1[i])==find(i)){if(imn.size()>1)mn1[i]=lmn[next(imn.begin())->second];elsemn1[i]=inf;}imn.erase({a[lmn[find(i)]],find(i)});if(a[i]<a[lmn[find(i)]])lmn[find(i)]=i;imn.insert({a[lmn[find(i)]],find(i)});}for(int vl,id,i=1;i<=n;i++){if(mx1[i]==0) id=mn1[i];else if(mn1[i]==0) id=mx1[i];else if(a[i]-a[mx1[i]]<=a[mn1[i]]-a[i]) id=mx1[i];else id=mn1[i];vl=(id<i?a[i]-a[id]:a[id]-a[i]);if(vl<mnm[find(i)]){mnm[find(i)]=vl;mni[find(i)]=id;}}for(int i=1;i<=n;i++)f2[i]=f[i];for(int i=1;i<=n;i++){if(mni[find(i)]==0) continue;int xx=find2(i),yy=find2(mni[find(i)]);if(xx!=yy){res+=mnm[find(i)];f2[xx]=yy;cnt--;}mni[find(i)]=0;}for(int i=1;i<=n;i++)f[i]=f2[i];}return res;
}
signed main() {ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);cin>>T;while(T--){cin>>n;for(int i=1;i<=n;i++)cin>>a[i];cout<<boruvka()<<endl;}return 0; 
}
http://www.rkmt.cn/news/5444.html

相关文章:

  • 第一篇博客
  • springboot的启动流程
  • 「微积分 A1」基础知识(连载中)
  • 萤火虫文旅年票、为什么能做到低至4.2元一张景区门票、还能高达50%的毛利润?
  • SAP 采购订单税率及含税金额取数
  • Jenkins 容器和 Kubernetes Agent
  • LGP7916 [CSP-S 2021] 交通规划 学习笔记
  • 详细介绍:【Kubernetes】常见面试题汇总(十四)
  • 教育行业API安全最佳实践:全知科技以国家标准引领数据防护新范式
  • Qt处理USB摄像头开发说明与QtMultimedia与V4L2融合应用
  • 拾忆录
  • 从零搭建RAG应用:跳过LangChain,掌握文本分块、向量检索、指代消解等核心技术实现
  • python高阶技巧
  • CSS纯文本渐变动效
  • Redssion
  • 提升系统可靠性:Air8000多串口硬件设计的黄金法则
  • 20250915笔记
  • enumerate函数
  • HyperWorks许可激活
  • OpenStack Nova instance 常见操作
  • 线性规划
  • 伪代码学习总结
  • 麒麟
  • 多品牌摄像机视频平台EasyCVR海康大华宇视视频平台统一接入方案
  • ubuntu安装mysql矩阵
  • 043-WEB攻防-PHP应用SQL注入符号拼接请求方法HTTP头JSON编码类
  • 玻璃2601
  • 2025 ICPC 网络赛2 E
  • 西电微机原理与接口技术笔记总结
  • Mysql查找含字符串表字段