当前位置: 首页 > 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.wxhsa.cn/company.asp?id=4945

相关文章:

  • java相关问题解答
  • 牛客 周赛106 20250904
  • 第一篇博客
  • 如何让多个按钮绑定到同一个事件上
  • STM32 HAL学习笔记:GC1808(PCM1808)的使用以及使用I2S+DMA读取
  • 完整教程:【视频系统】技术汇编
  • MSTP 单域
  • 阿里云百炼平台使用避坑记录 - 详解
  • springboot的run
  • ubuntu服务器docker日期安装mysql
  • springboot的启动流程
  • 萤火虫旅行网和萤火虫文旅的关系是什么
  • 「微积分 A1」基础知识(连载中)
  • 第2周-预习作业
  • P12546 [UOI 2025] Convex Array
  • 一个新词:测试可靠性
  • CF827F Dirty Arkadys Kitchen
  • P2839 [国家集训队] middle
  • wuti
  • 友链
  • 向量化存储与知识图谱的比较
  • 力扣17题 电话号码的字母组合
  • 萤火虫文旅年票、为什么能做到低至4.2元一张景区门票、还能高达50%的毛利润?
  • ubuntu服务器docker容器安装nacos
  • PWN手的成长之路-02-r3m4ke
  • SAP 采购订单税率及含税金额取数
  • 深入解析:Linux x86 stability和coredump
  • 9.15更新linux命令
  • Jenkins 容器和 Kubernetes Agent
  • LGP7916 [CSP-S 2021] 交通规划 学习笔记