qwq(明明可以直接分治过掉的)

但是还是当作联系了

首先,对于这种点的题,很显然的套路,我们要维护一个子树\(mx[i],mn[i]\)分别表示每个维度的最大值和最小值

(这里有一个要注意的东西!就是我们\(up\)的时候,要判断一下当前是否还有左/右儿子)

bool operator< (KD a,KD b)
{
return a.d[ymh]<b.d[ymh];
}
void up(int root)
{
for (int i=0;i<=1;i++)
{
if (t[root].l)
{
t[root].mn[i]=min(t[root].mn[i],t[t[root].l].mn[i]);
t[root].mx[i]=max(t[root].mx[i],t[t[root].l].mx[i]);
}
if (t[root].r)
{
t[root].mn[i]=min(t[root].mn[i],t[t[root].r].mn[i]);
t[root].mx[i]=max(t[root].mx[i],t[t[root].r].mx[i]);
}
}
}
void build(int &x,int l,int r,int dd)
{
ymh = dd;
int mid = l+r >> 1;
x = mid;
nth_element(t+l,t+x,t+r+1);
for (int i=0;i<=1;i++) t[x].mn[i]=t[x].mx[i]=t[x].d[i];
if (l<x) build(t[x].l,l,mid-1,dd^1);
if (x<r) build(t[x].r,mid+1,r,dd^1);
up(x);
}

其实这个题最重要的是估价函数该怎么写。

首先我们很容易发现,因为我们要求的是这个子树理论上到那个点的最短距离,所以我们需要这么考虑,如果当前点的坐标在\(mn到mx\)之间的话,那么理论上的最短距离就是0,否则就是当前这一维度距离\(mn和mx\)较近的距离

double calc(KD a,KD b)
{
double tmp=0;
for (int i=0;i<=1;i++)
{
if (b.d[i]<a.mn[i]) tmp=tmp+(a.mn[i]-b.d[i])*(a.mn[i]-b.d[i]);
else if (b.d[i]>a.mx[i]) tmp=tmp+(a.mx[i]-b.d[i])*(a.mx[i]-b.d[i]);
}
return sqrt(tmp);
}

其实剩下的就是和普通的kdtree差不多了

直接上就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2e5+1e2;
struct KD{
double mx[4],mn[4],d[4];
int l,r;
};
KD t[maxn],now;
int n,m,root;
int ymh;
double ans;
double tmp;
int ii =0;
bool operator< (KD a,KD b)
{
return a.d[ymh]<b.d[ymh];
}
void up(int root)
{
for (int i=0;i<=1;i++)
{
if (t[root].l)
{
t[root].mn[i]=min(t[root].mn[i],t[t[root].l].mn[i]);
t[root].mx[i]=max(t[root].mx[i],t[t[root].l].mx[i]);
}
if (t[root].r)
{
t[root].mn[i]=min(t[root].mn[i],t[t[root].r].mn[i]);
t[root].mx[i]=max(t[root].mx[i],t[t[root].r].mx[i]);
}
}
}
void build(int &x,int l,int r,int dd)
{
ymh = dd;
int mid = l+r >> 1;
x = mid;
nth_element(t+l,t+x,t+r+1);
for (int i=0;i<=1;i++) t[x].mn[i]=t[x].mx[i]=t[x].d[i];
if (l<x) build(t[x].l,l,mid-1,dd^1);
if (x<r) build(t[x].r,mid+1,r,dd^1);
up(x);
}
double getdis(int a,KD b)
{
if (!a) return 0;
double tmp=0;
for (int i=0;i<=1;i++)
{
tmp=tmp+(t[a].d[i]-b.d[i])*(t[a].d[i]-b.d[i]);
}
return sqrt(tmp);
}
double calc(KD a,KD b)
{
double tmp=0;
for (int i=0;i<=1;i++)
{
if (b.d[i]<a.mn[i]) tmp=tmp+(a.mn[i]-b.d[i])*(a.mn[i]-b.d[i]);
else if (b.d[i]>a.mx[i]) tmp=tmp+(a.mx[i]-b.d[i])*(a.mx[i]-b.d[i]);
}
return sqrt(tmp);
}
void query(int x)
{
if (!x) return;
double d1 = calc(t[t[x].l],now);
double d2 = calc(t[t[x].r],now);
double d = getdis(x,now);
if (d<tmp && d!=0) tmp = d;
if (d==0) ii++;
if (d1<d2)
{
if (d1<tmp) query(t[x].l);
if (d2<tmp) query(t[x].r);
}
else
{
if (d2<tmp) query(t[x].r);
if (d1<tmp) query(t[x].l);
}
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
for (int j=0;j<=1;j++) t[i].d[j]=read();
build(root,1,n,0);
tmp = 1e18;
for (int i=1;i<=n;i++)
{
ii=0;
now = t[i];
query(root);
if (ii>1) tmp=0;
}
printf("%.4lf",tmp);
return 0;
}

洛谷1429 平面最近点对(KDTree)的更多相关文章

  1. (洛谷 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 ...

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

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

  3. Luogu 1429 平面最近点对 | 平面分治

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

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

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

  5. 洛谷 P6362 平面欧几里得最小生成树

    题目描述 平面上有 \(n\) 个点,第 \(i\) 个点坐标为 \((x_i, y_i)\).连接 \(i, j\) 两点的边权为 \(\sqrt{(x_i - x_j) ^ 2 + (y_i - ...

  6. 【洛谷P4148】简单题(kd-tree)

    传送门 题意: 给出一个\(n*n\)的棋盘,现在有两种操作:一种是某个格子里的数字加上\(A\),另一种是询问矩阵和. 空间限制:\(20MB\),强制在线. 思路: 直接\(kd-tree\)来搞 ...

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

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

  8. 洛谷 P4148 简单题 KD-Tree 模板题

    Code: //洛谷 P4148 简单题 KD-Tree 模板题 #include <cstdio> #include <algorithm> #include <cst ...

  9. 洛谷4631 [APIO2018] Circle selection 选圆圈 (KD树)

    qwq纪念AC450 一开始想这个题想复杂了. 首先,正解的做法是比较麻烦的. qwqq 那么就不如来一点暴力的东西,看到平面上点的距离的题,不难想到\(KD-Tree\) 我们用类似平面最近点对那个 ...

随机推荐

  1. 微信小程序--聊天室小程序(云开发)

    微信小程序 -- 聊天室小程序(云开发) 从微信小程序开发社区更新watch接口之后,一直在构思这个项目.项目已经完成很久,但是一直都没有空写一篇博客记录展示一下. 开源地址 wx-cloud-im: ...

  2. 程序解决十苹果问题 Java

    程序解决十苹果问题 Java 题目:10个苹果,其中有9个重量相同,剩余1个相比其它重量不同(或重或轻,不得而知),使用天平比较三次,找出重量特殊的那一个 import org.junit.Test; ...

  3. 常用ADB命令汇总

    网络连接 通过TCP/IP连接设备 adb connect <ip:port> 断开已有的TCP/IP连接 adb disconnect <ip:port> 监听设备上指定的端 ...

  4. Mybatis源码解析4——SqlSession

    上一篇文章中,我们介绍了 SqlSessionFactory 的创建过程,忘记了的,可以回顾一下,或者看下下面这张图也行. 接下来,可乐讲给大家介绍 Mybatis 中另一个重量级嘉宾--SqlSes ...

  5. SQL语句之基本使用

    1.sql语法 一些重要的SQL命令: SELECT - 从数据库中提取数据 UPDATE - 更新数据库中的数据 DELETE - 从数据库中删除数据 INSERT INTO - 向数据库中插入新数 ...

  6. python使用UTF-8写入CSV中文乱码

    使用encoding='utf-8',写入的文档是乱码. 解决办法: 修改encoding='utf-8-sig' 关于文件open()函数: open(path,'-模式-',encoding='u ...

  7. Python - 执行cmd命令

    python操作cmd 我们通常可以使用os模块的命令进行执行cmd 方法一:os.system os.system(执行的命令) # 源码 def system(*args, **kwargs): ...

  8. Python - pip-review 库

    使用 pip-review 库(推荐) 安装库 pip install pip-review 检查是否有需要更新的包 > pip-review scikit-learn==0.23.2 is a ...

  9. ABP 极简入门教程(二 MVC方式显示数据)

    增加显示菜单 Sample.Web.MVC项目中找到startup目录打开SampleNavigationProvider.cs,根据现有内容添加以下内容 .AddItem( new MenuItem ...

  10. 理解MySQL回表

    回表就是先通过数据库索引扫描出数据所在的行,再通过行主键id取出索引中未提供的数据,即基于非主键索引的查询需要多扫描一棵索引树. 因此,可以通过索引先查询出id字段,再通过主键id字段,查询行中的字段 ...