嘟嘟嘟




题意:给定\(n\)个二维平面上的点\((x_i, y_i)\),求离每一个点最近的点得距离的平方。(\(n \leqslant 1e5\))




这就是k-d tree入门题了。

k-d tree这东西跟平衡树有点像,但却不一样,而且查询的最坏复杂度是\(O(\sqrt{n})\)的。

首先推荐两篇博客:

K-D tree 数据结构

k-d tree入门

在众多博客之中算是非常好的。




先说一下建树。

建树可以理解为多维平衡树(但愿能这么叫),所以是平衡树结构。不过没有旋转等一系列复杂的操作。

然后对于每一层,我们按其中一个维度划分,并取这个维度的中位数上的点作为这个节点的值\(val\),然后把在这一维小于\(val\)的递归到左子树处理,大于的递归到右子树处理。

那么可以想象出来,如果是二维的话,每一个节点都是一个矩形。

至于我们选哪一个维度,一种比较“平衡”的做法是算出当前区间所有点在每一维上的方差\(s ^ 2\),然后选方差最大的那一维进行划分。

不过实际上很少有题会这么卡,所以轮流换一维建树就行。比如当前层是按第\(x\)维建树,总共有\(d\)维,那么他的下一层按\((x + 1) \ \ mod \ \ d\)划分就行。

优化一下,用nth_element代替sort找中位数,建树复杂度就是\(O(n log n)\)的。

In void pushup(int now)		//pushup可能写的麻烦了
{
for(int i = 0; i < 2; ++i)
{
if(t[now].ch[0])
{
t[now].Min[i] = min(t[now].Min[i], t[t[now].ch[0]].Min[i]);
t[now].Max[i] = max(t[now].Max[i], t[t[now].ch[0]].Max[i]);
}
if(t[now].ch[1])
{
t[now].Min[i] = min(t[now].Min[i], t[t[now].ch[1]].Min[i]);
t[now].Max[i] = max(t[now].Max[i], t[t[now].ch[1]].Max[i]);
}
}
}
In void build(int& now, int d, int L, int R)
{
if(L > R) return;
int mid = (L + R) >> 1;
dim = d;
nth_element(a + L, a + mid, a + R + 1);
t[now = ++tcnt] = a[mid]; t[now].id = a[mid].id;
t[now].Min[0] = t[now].Max[0] = t[now].d[0];
t[now].Min[1] = t[now].Max[1] = t[now].d[1];
t[now].ch[0] = t[now].ch[1] = 0;
build(t[now].ch[0], d ^ 1, L, mid - 1);
build(t[now].ch[1], d ^ 1, mid + 1, R);
pushup(now);
}



建树看起来很优美,但是查询就不是了。
查询可以说是暴力+A*剪枝。
啊对了,我的查询和上面博客里的不一样,是asdfz的tyx大佬给我讲的。
一下以二维k-d tree为例:
暴力自然不必说,遍历整棵树即可。
关键是剪枝。
假如当前答案是$ans$(开成全局变量),那么如果要查询的点和矩形的最近距离都比$ans$大的话,自然不进入这个矩形(子树)查找。
![](https://img2018.cnblogs.com/blog/1284378/201901/1284378-20190115090226183-2051604632.png)
也就是上面的蓝色线。(很显然对吧)
这里在补充一下,蓝色线的垂足可能没有点,但因为这是个估价函数,即最优的情况还比答案劣,我们就不进入这个子树。
那么怎么求这个距离呢?
其实就是把矩形确定下来。
那么对于每一维,我们维护一个min和max就行啦。
然后观察这个距离,其实就是查询点哪一维不在矩形里面,就把这一维的贡献算上。
最优复杂度显然是$O(log n)$,但我也不知道为啥最坏复杂度是$O(\sqrt{n})$。
```c++
ll ans = INF;
In ll dis(int now, ll* d)
{
ll ret = 0;
for(int i = 0; i d[i]) ret += (d[i] - t[now].Min[i]) * (d[i] - t[now].Min[i]);
return ret;
}

In void query(int now, int id)

{

if(!now) return;

if(t[now].id ^ id) ans = min(ans, dis(now, b[id].d));

ll disL = price(t[now].ch[0], b[id].d), disR = price(t[now].ch[1], b[id].d);

if(disL < ans) query(t[now].ch[0], id);

if(disR < ans) query(t[now].ch[1], id); //千万不要写else if!!

}

代码还是很简单的。
</br>
k-d tree还可以支持查询最近的k个点,准备今天学学。
完整代码
```c++
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const ll INF = 1e18;
const db eps = 1e-8;
const int maxn = 1e5 + 5;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
} int n, dim = 0;
struct Tree
{
int ch[2], id;
ll d[2], Min[2], Max[2];
In bool operator < (const Tree& oth)const
{
return d[dim] < oth.d[dim];
}
}t[maxn << 2], a[maxn], b[maxn];
int root, tcnt = 0; In void pushup(int now) //pushup可能写的麻烦了
{
for(int i = 0; i < 2; ++i)
{
if(t[now].ch[0])
{
t[now].Min[i] = min(t[now].Min[i], t[t[now].ch[0]].Min[i]);
t[now].Max[i] = max(t[now].Max[i], t[t[now].ch[0]].Max[i]);
}
if(t[now].ch[1])
{
t[now].Min[i] = min(t[now].Min[i], t[t[now].ch[1]].Min[i]);
t[now].Max[i] = max(t[now].Max[i], t[t[now].ch[1]].Max[i]);
}
}
}
In void build(int& now, int d, int L, int R)
{
if(L > R) return;
int mid = (L + R) >> 1;
dim = d;
nth_element(a + L, a + mid, a + R + 1);
t[now = ++tcnt] = a[mid]; t[now].id = a[mid].id;
t[now].Min[0] = t[now].Max[0] = t[now].d[0];
t[now].Min[1] = t[now].Max[1] = t[now].d[1];
t[now].ch[0] = t[now].ch[1] = 0;
build(t[now].ch[0], d ^ 1, L, mid - 1);
build(t[now].ch[1], d ^ 1, mid + 1, R);
pushup(now);
} ll ans = INF;
In ll dis(int now, ll* d)
{
ll ret = 0;
for(int i = 0; i < 2; ++i) ret += (t[now].d[i] - d[i]) * (t[now].d[i] - d[i]);
return ret;
}
In ll price(int now, ll* d)
{
ll ret = 0;
for(int i = 0; i < 2; ++i)
if(t[now].Max[i] < d[i]) ret += (d[i] - t[now].Max[i]) * (d[i] - t[now].Max[i]);
else if(t[now].Min[i] > d[i]) ret += (d[i] - t[now].Min[i]) * (d[i] - t[now].Min[i]);
return ret;
} In void query(int now, int id)
{
if(!now) return;
if(t[now].id ^ id) ans = min(ans, dis(now, b[id].d));
ll disL = price(t[now].ch[0], b[id].d), disR = price(t[now].ch[1], b[id].d);
if(disL < ans) query(t[now].ch[0], id);
if(disR < ans) query(t[now].ch[1], id); //千万不要写else if!!
} int main()
{
int T = read();
while(T--)
{
tcnt = 0;
n = read();
for(int i = 1; i <= n; ++i) a[i].d[0] = read(), a[i].d[1] = read(), a[i].id = i, b[i] = a[i];
build(root, 0, 1, n);
for(int i = 1; i <= n; ++i)
{
ans = INF;
query(root, i);
write(ans), enter;
}
}
return 0;
}

HDU2966 In case of failure(浅谈k-d tree)的更多相关文章

  1. 浅谈k短路算法

    An Old but Classic Problem 给定一个$n$个点,$m$条边的带正权有向图.给定$s$和$t$,询问$s$到$t$的所有权和为正路径中,第$k$短的长度. Notice 定义两 ...

  2. kd树 hdu2966 In case of failure

    传送门:pid=2966" target="_blank">点击打开链接 题意:给n个点,求对于每一个点到近期点的欧几里德距离的平方. 思路:看鸟神博客学kd树劲啊 ...

  3. Service Cloud 零基础(一)Case 浅谈

    本片参考:https://resources.docs.salesforce.com/222/latest/en-us/sfdc/pdf/salesforce_case_implementation_ ...

  4. iOS开发之浅谈MVVM的架构设计与团队协作

    今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

  5. 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

    http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...

  6. 浅谈iOS中MVVM的架构设计与团队协作

    说到架构设计和团队协作,这个对App的开发还是比较重要的.即使作为一个专业的搬砖者,前提是你这砖搬完放在哪?不只是Code有框架,其他的东西都是有框架的,比如桥梁等等神马的~在这儿就不往外扯了.一个好 ...

  7. 浅谈Swift语法

    Apple 在2014年6月的WWDC公布了一款新型的开发语言,很多美国程序猿的价值观貌似和我们非常大的不同,在公布的时候我们能够听到,场下的欢呼声是接连不断的.假设换作我们,特别是像有Objecti ...

  8. 浅谈OCR之Onenote 2010

    原文:浅谈OCR之Onenote 2010 上一次我们讨论了Tesseract OCR引擎的用法,作为一款老牌的OCR引擎,目前已经开源,最新版本3.0中更是加入了中文OCR功能,再加上Google的 ...

  9. IOS中 浅谈iOS中MVVM的架构设计与团队协作

    今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

随机推荐

  1. [Noip2015PJ] 求和

    Description 一条狭长的纸带被均匀划分出了 \(n\) 个格子,格子编号从 \(1\) 到 \(n\) .每个格子上都染了一种颜色 \(color_i\) 用 \([1,m]\) 当中的一个 ...

  2. R语言实战 —— 常见问题解决方法

    1.不存在叫XXX这个名字的程序包 > library(reshape) Error in library(reshape) : 不存在叫‘reshape’这个名字的程辑包 解决方法:先安装,后 ...

  3. TCP/IP 详解

    分层 每一层负责不同的功能:     链路层 有时也称作数据链路层或网络接口层, 通常包括操作系统中的设备驱动程序和计算机 中对应的网络接口卡.它们一起处理与电缆(或其他任何传输媒介)的物理接口细节. ...

  4. 【ichart】简单的统计图表ichart.js的使用

    1.首先下载,点击下载 2.只需要这一个js,粘贴赋值到自己项目中即可.   3.引入js <script type="text/javascript" src=" ...

  5. Hive数据倾斜

    数据倾斜是进行大数据计算时最经常遇到的问题之一.当我们在执行HiveQL或者运行MapReduce作业时候,如果遇到一直卡在map100%,reduce99%一般就是遇到了数据倾斜的问题.数据倾斜其实 ...

  6. minitab 输入一串数字

    有时候,我们要向minitab的worksheet输入一串串的数字,很是麻烦. 相如一串数字我们在一个pdf文件存着 那么效率最低的输入方法就是一个一个的输入,"Enter"进入下 ...

  7. How to Find the Standard Deviation in Minitab

    Standard deviation, represented by the Greek Letter sigma σ, is a measure of dispersement in statist ...

  8. js 键盘码

    键盘各按键对应的数字 keycode 9 = Tab keycode 12 = Clear keycode 13 = Enter keycode 16 = Shift keycode 17 = Con ...

  9. IDEA项目搭建十——使用slf4j和logback进行日志记录

    .简介 java里面日志分为两部分一个门面.一个实现,我们所熟知的SLF4j.Log4j.Log4j2.Logback的日志组件slf4j是门面提供的统一的入口,具体实现由log4j.log4j2.l ...

  10. aws s3文件上传设置accesskey、secretkey、sessiontoken

    背景: 最近跟进的项目会封装aws S3资源管理细节,对外提供获取文件上传凭证的API,业务方使用获取到的凭证信息直接请求aws进行文件上传.因此,测试过程需要验证S3文件上传的有效性.aws官网有提 ...