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. MySQL-存储引擎-Myisam

    mysql> create table myisam_char(name char(10)) engine=myisam; Query OK, 0 rows affected (0.01 sec ...

  2. redux的使用

    1.redux的使用 核心概念 action 动作的对象 包含2个属性 type:标识属性, 值为字符串, 唯一, 必要属性 data:数据属性, 值类型任意, 可选属性 例子:{ type: 'AD ...

  3. 整理之Service

    Service 基础 一个Service的基本结构 class MyService : Service() { private val mBinder = MyBinder() override fu ...

  4. GUI容器之布局管理器

    布局管理器 布局管理器:frame.setLayout(); 默认值为new flowLayout() 流式布局 frame.setLayout(new FlowLayout(FlowLayout.R ...

  5. Sentry For React 完整接入详解(2021 Sentry v21.8.x)前方高能预警!三万字,慎入!

    内容源于:https://docs.sentry.io/platforms/javascript/guides/react/ 系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - ...

  6. “ShardingCore”是如何针对分表下的分页进行优化的

    分表情况下的分页如何优化 首先还是要给自己的开原框架打个广告 sharding-core 针对efcore 2+版本的分表组件,首先我们来快速回顾下目前市面上分表下针对分页常见的集中解决方案 分表解决 ...

  7. WEB漏洞——CSRF、SSRF

    CSRF漏洞 CSRF( Cross- site request forgery,跨站请求伪造)也被称为 One Click Attack或者 Session Riding,通常缩写为CSRF或者XS ...

  8. c# List集合类常用操作:二、增加

    所有操作基于以下类 class Employees { public int Id { get; set; } public string Name { get; set; } public stri ...

  9. 手工添加数据到Chart

    private void button1_Click(object sender, EventArgs e) { //清除Series chart1.Series.Clear(); Random ra ...

  10. AtCoder Regular Contest 069 D - Menagerie 枚举起点 模拟递推

    arc069.contest.atcoder.jp/tasks/arc069_b 题意:一堆不明身份的动物排成一圈,身份可能是羊或狼,羊一定说实话,狼一定说假话.大家各自报自己的两边是同类还是不同类, ...