题目描述

平面上有 \(n\) 个点,第 \(i\) 个点坐标为 \((x_i, y_i)\)。连接 \(i, j\) 两点的边权为 \(\sqrt{(x_i - x_j) ^ 2 + (y_i - y_j) ^ 2}\)。求最小生成树的边权之和。

输入格式

第一行一个整数 \(n\)。

接下来 \(n\) 行,每行输入两个整数 \(x_i, y_i\)​。

输出格式

输出一行一个实数,表示答案。

当你的答案与标准输出的绝对误差或相对误差在 \(10^{-6}\) 内时,就会被视为正确。

输入输出样例

输入 #1

4
0 0
1 2
-1 2
0 4

输出 #1

6.472136

说明/提示

样例解释 1

该样例中,最小生成树如下图所示:

边权之和为 \(2 \sqrt{5} + 2 \approx 6.47213595500\)

数据规模与约定

对于 \(50\%\) 的数据,\(n \le 5000\)。

对于 \(100\%\) 的数据,\(3 \le n \le 10 ^ 5\),\(\lvert x_i \rvert, \lvert y_i \rvert \le 10 ^ 5\)。

分析

边数太多,肯定不能用 \(Kruskal\)

\(n^2\) 的 \(Prim\) 也过不去

所以可以用 \(Boruvka\) 算法

找到某一个点距离最近的点用 \(kdtree\) 查询就行了

查询的时候加一个剪枝,初始的答案不要置为无穷大,要设为当前联通块内的最优解

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e5+5;
int cnt,orz,n,rt,x[maxn],y[maxn];
struct KDT{
int mn[2],mx[2],d[2],lc,rc,id,col;
friend bool operator <(const KDT& A,const KDT& B){
return A.d[orz]<B.d[orz];
}
}tr[maxn],jl[maxn];
void push_up(rg int da){
rg int lc=tr[da].lc,rc=tr[da].rc;
for(rg int i=0;i<2;i++){
tr[da].mn[i]=tr[da].mx[i]=tr[da].d[i];
if(lc){
tr[da].mx[i]=std::max(tr[da].mx[i],tr[lc].mx[i]);
tr[da].mn[i]=std::min(tr[da].mn[i],tr[lc].mn[i]);
}
if(rc){
tr[da].mx[i]=std::max(tr[da].mx[i],tr[rc].mx[i]);
tr[da].mn[i]=std::min(tr[da].mn[i],tr[rc].mn[i]);
}
}
}
int build(rg int l,rg int r,rg int pl){
orz=pl;
rg int mids=(l+r)>>1;
std::nth_element(jl+l,jl+mids,jl+r);
tr[mids]=jl[mids];
if(l<mids) tr[mids].lc=build(l,mids-1,!pl);
if(mids<r) tr[mids].rc=build(mids+1,r,!pl);
push_up(mids);
return mids;
}
long long getdis(rg int ax,rg int ay,rg int bx,rg int by){
return 1LL*(ax-bx)*(ax-bx)+1LL*(ay-by)*(ay-by);
}
long long sqr(rg int aa){
return 1LL*aa*aa;
}
long long mindis(rg int da,rg int xx,rg int yy){
rg long long mans=0;
mans+=sqr(std::max(0,xx-tr[da].mx[0])+std::max(0,tr[da].mn[0]-xx));
mans+=sqr(std::max(0,yy-tr[da].mx[1])+std::max(0,tr[da].mn[1]-yy));
return mans;
}
long long nans=0x3f3f3f3f3f3f3f3f;
int haha=0;
void cx(rg int da,rg int xx,rg int yy,rg int zz){
if(!da) return;
rg long long tmp=getdis(xx,yy,tr[da].d[0],tr[da].d[1]);
if(tr[da].col!=zz && nans>tmp){
nans=tmp,haha=tr[da].id;
}
tmp=mindis(da,xx,yy);
if(tmp>=nans) return;
rg long long tmp1=0x3f3f3f3f3f3f3f3f,tmp2=0x3f3f3f3f3f3f3f3f;
if(tr[da].lc) tmp1=mindis(tr[da].lc,xx,yy);
if(tr[da].rc) tmp2=mindis(tr[da].rc,xx,yy);
if(tmp1<tmp2){
if(tmp1<=nans) cx(tr[da].lc,xx,yy,zz);
if(tmp2<=nans) cx(tr[da].rc,xx,yy,zz);
} else {
if(tmp2<=nans) cx(tr[da].rc,xx,yy,zz);
if(tmp1<=nans) cx(tr[da].lc,xx,yy,zz);
}
}
double ans=0;
int bes[maxn],fa[maxn],tot;
long long bes2[maxn];
int zhao(rg int xx){
if(xx==fa[xx]) return xx;
return fa[xx]=zhao(fa[xx]);
}
double getdis2(rg int ax,rg int ay,rg int bx,rg int by){
return sqrt(1.0*(ax-bx)*(ax-bx)+1.0*(ay-by)*(ay-by));
}
int main(){
n=read();
for(rg int i=1;i<=n;i++) jl[i].d[0]=read(),jl[i].d[1]=read(),jl[i].id=jl[i].col=i,x[i]=jl[i].d[0],y[i]=jl[i].d[1];
for(rg int i=1;i<=n;i++) fa[i]=i;
rt=build(1,n,0);
rg int tmp=0;
while(tot<n-1){
for(rg int i=1;i<=n;i++) bes[i]=0,bes2[i]=0x3f3f3f3f3f3f3f3f;
for(rg int i=1;i<=n;i++){
tmp=zhao(i);
nans=bes2[tmp],haha=-1;
cx(rt,x[i],y[i],tmp);
if(haha==-1) continue;
if(bes2[tmp]>nans){
bes2[tmp]=nans;
bes[tmp]=haha;
} else if(bes2[tmp]==nans){
if(bes[tmp]<haha) bes[tmp]=haha;
}
}
for(rg int i=1;i<=n;i++){
tmp=zhao(i);
if(bes[tmp] && tmp!=zhao(bes[tmp])){
fa[tmp]=zhao(bes[tmp]);
ans+=sqrt((double)bes2[tmp]);
tot++;
}
}
for(rg int i=1;i<=n;i++){
tr[i].col=zhao(tr[i].id);
}
}
printf("%.6f\n",ans);
return 0;
}

洛谷 P6362 平面欧几里得最小生成树的更多相关文章

  1. 洛谷P2568 GCD (欧拉函数/莫比乌斯反演)

    P2568 GCD 题目描述 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对. 输入输出格式 输入格式: 一个整数N 输出格式: 答案 输入输出样例 输入 ...

  2. (洛谷 P1429 平面最近点对(加强版) || 洛谷 P1257 || Quoit Design HDU - 1007 ) && Raid POJ - 3714

    这个讲的好: https://phoenixzhao.github.io/%E6%B1%82%E6%9C%80%E8%BF%91%E5%AF%B9%E7%9A%84%E4%B8%89%E7%A7%8D ...

  3. 洛谷P4180 [BJWC2010]次小生成树(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  4. 洛谷 P1257 平面上的最接近点对 题解

    P1257 平面上的最接近点对 题目描述 给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的. 输入格式 第一行:n:2≤n≤10000 接下来n行:每行两 ...

  5. 洛谷 - P2158 - 仪仗队 - 欧拉函数

    https://www.luogu.org/problemnew/show/P2158 好像以前有个妹子收割铲也是欧拉函数. 因为格点直线上的点,dx与dy的gcd相同,画个图就觉得是欧拉函数.但是要 ...

  6. 洛谷P1257 平面上的最接近点对

    n<=10000个点,求欧几里德距离最小的一对点. 经典分治,把这些点按x排序,分成两半,每边分别算答案,答案是左边的最小,右边的最小,左右组起来的最小三者的最小.发现只有左右组的有点难写. 假 ...

  7. 洛谷 - P2568 - GCD - 欧拉函数

    https://www.luogu.org/problemnew/show/P2568 统计n以内gcd为质数的数的个数. 求 \(\sum\limits_p \sum\limits_{i=1}^{n ...

  8. 题解 洛谷P5259【欧稳欧再次学车】

    实际上没什么可说的,暴力大模拟就好. 一定要开long long! 一定要开long long! 一定要开long long! (不然会炸数据的!!!) //Stand up for the fait ...

  9. 洛谷 P1429 平面最近点对(加强版) (分治模板题)

    题意:有\(n\)个点对,找到它们之间的最短距离. 题解:我们先对所有点对以\(x\)的大小进行排序,然后分治,每次左右二等分递归下去,当\(l+1=r\)的时候,我们计算一下距离直接返回给上一层,若 ...

随机推荐

  1. Ubuntu系统下电脑驱动的安装(wifi无线网卡)

    今天给自己的笔记本电脑安装了新的Ubuntu 16.04但是安装之后发现wifi无法启用.这里特说明解决过程. 首先,网上的大部分教程是 选择"系统设置",点击"软件和更 ...

  2. JavaDailyReports10_04

    修改后的出题系统 1.添加用户自定义是否出现乘除法,自由选择符号和个数,并且可以自定义操作数的取值范围. 1 /* 2 * 2.可定制(数量/打印方式):输入大的数量值,测试一下系统是否崩溃,反向查找 ...

  3. windows使用sdelete安全的删除文件

    SDelete是一款来自于微软Sysinternals[1]的应用.使用SDelete可以安全的删除现有文件,以及安全地擦除磁盘的未分配部分中存在的数据(包括已经删除或加密的文件).SDelete使用 ...

  4. 两个字搞定DDD(领域驱动设计),DDD脱水版(一)修订版

    摘自微信公众号丁辉的软件架构说

  5. C语言实现的多线程定时器

    目录 1. 大致功能介绍 2. API库介绍 3. 一个例子 4. 库文件源码 注意事项 1. 大致功能介绍 实现任务列表,定时器会间隔一段时间遍历列表发现要执行的任务 任务列表中的所有任务并行执行 ...

  6. 第13章节 BJROBOT 雷达跟随【ROS全开源阿克曼转向智能网联无人驾驶车】

    雷达跟随说明:注意深度摄像头的 USB 延长线,可能会对雷达扫描造成影响, 所以在雷达跟随前,把深度摄像头的 USB 延长线取下.另外雷达跟随范围大概是前方 50cm 和 120°内扫描到的物体都可以 ...

  7. 如何利用Typora编写博客,快速发布到多平台?

    在不同的平台发布同样的文章,最让人头疼的就是图片问题,如果要手动一个个去重新上传,耗时耗力,还容易搞错.下面分享的方法,可以将Typora编写的文章快速发布到CSDN.微信公众号.博客园.简书等平台. ...

  8. springboot 不同环境读取不同配置

    1. 3个配置文件(更多环境可以建多个): application.properties  (公共配置文件) application-dev.properties  (开发环境) applicatio ...

  9. Java中定时器Timer致命缺点(附学习方法)

    简介 这篇文章我一直在纠结到底要不要写,不想写一来因为定时器用法比较简单,二来是面试中也不常问.后来还是决定写了主要是想把自己分析问题思路分享给大家,让大家在学习过程中能够参考,学习态度我相信大部分人 ...

  10. MyBatis初级实战之二:增删改查

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...