嘟嘟嘟

题意:给定\(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\)大的话,自然不进入这个矩形(子树)查找。

也就是上面的蓝色线。(很显然对吧)
这里在补充一下,蓝色线的垂足可能没有点,但因为这是个估价函数,即最优的情况还比答案劣,我们就不进入这个子树。
那么怎么求这个距离呢?
其实就是把矩形确定下来。
那么对于每一维,我们维护一个min和max就行啦。
然后观察这个距离,其实就是查询点哪一维不在矩形里面,就把这一维的贡献算上。
最优复杂度显然是\(O(log n)\),但我也不知道为啥最坏复杂度是\(O(\sqrt{n})\)。

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!!
}

代码还是很简单的。

k-d tree还可以支持查询最近的k个点,准备今天学学。
完整代码

#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;
}

转载于:https://www.cnblogs.com/mrclr/p/10270042.html

HDU2966 In case of failure(浅谈k-d tree)相关推荐

  1. verilog case语句_浅谈Design Compiler -- Verilog语言结构到门级的映射

    昨天的文章中,我们了解到Design Compiler(DC)作为Synopsys公司开发的一款用于电路综合的EDA工具,在全球数字电路市场去得了巨大的成功,它的设计初衷是将用Verilog HDL语 ...

  2. 浅谈K短路算法(KSP)之二(YEN .J算法求解)

    对于具有n个顶点和m条边且边的权值非负的简单图(无重边和环),K短路,是指的起点s到终点t的最短路径中第k个最小的.K短路分为有限制的K短路和无限制的K短路,有限制的K短路是指求得的路径中不含有回路( ...

  3. 浅谈K短路算法(KSP)之一(A*算法求解)

    对于具有n个顶点和m条边且边的权值非负的简单图(无重边和环),K短路,是指的起点s到终点t的最短路径中第k个最小的.K短路分为有限制的K短路和无限制的K短路,有限制的K短路是指求得的路径中不含有回路( ...

  4. 同花顺如何切换k线_K线之形态学:浅谈纸白银产品该如何去做好交易?

    K线之形态学:浅谈纸白银产品该如何去做好交易? 由于疫情期间,明显感觉到今年做投资理财的朋友多了,特别是银行的纸产品,我是分析外盘伦敦银伦敦金为主,自己也是只操作外盘产品.国内的不管是纸白银或者TD白 ...

  5. 浅谈软件开发工具CASE在软件项目开发中发挥的作用认识

    浅谈软件开发工具CASE在软件项目开发中发挥的作用认识 内容摘要:阐述了CASE工具作为 一种开发环境在软件项目开发中所起到的开发及管理作用.CASE工具实际上是把原先由手工完成的开发过程转变为以自动 ...

  6. 【JVM调优】JVM内存管理调优浅谈

    什么是JVM Java Virtual Machine,Java虚拟机 Java虚拟机有自己完善的硬件架构,如处理器.堆栈等,还具有相应的指令系统. Java虚拟机本质上就是一个程序,当它在命令行上启 ...

  7. 浅谈OCR之Onenote 2010

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

  8. 我的家乡网页设计_Graphic Design|康石石浅谈LOGO设计在作品集中的创作方法

    写在前面的话 平面设计范畴极广,其领域不仅限于常见的版式设计.海报设计.LOGO设计.VI设计.书籍装帧.广告设计.网页设计.在艺术留学申请过程中,学习平面设计的同学们需依据目标院校对作品集项目及页数 ...

  9. aes key长度_原创 | 浅谈Shiro反序列化获取Key的几种方式

    点击"关注"了解更多信息 关于Apache Shiro反序列化 在shiro≤1.2.4版本,默认使⽤了CookieRememberMeManager,由于AES使用的key泄露, ...

最新文章

  1. android数据库查找一个字符,Android - 如何在Firebase数据库中对字符串进行简单搜索?_android_开发99编程知识库...
  2. AI圈真魔幻!谷歌最新研究表明卷积在NLP预训练上竟优于Transformer?LeCun暧昧表态...
  3. 部分 II. Voice over IP
  4. 腾讯在线教育小程序开发实践之路
  5. ngrx里StoreModule.forFeature(‘example‘, reducers)运行时的数据结构
  6. java in out 参数_总是避免Java中的in-out参数?
  7. 怎么成为开源贡献者_开源如何成为您下一份工作的门户
  8. CSS中expression怎么用? CSS expression详解
  9. 26. Remove Duplicates from Sorted Array【easy】
  10. NPN和PNP的区别和总结
  11. 统信UOS_arm64开发环境配置
  12. python tcl tk_如何解决Mac版关于python3.5.X的Tcl/Tk (8.5.9) 的警告?
  13. 横河川仪压力变送器调零_横河EJA系列的变送器调零如何操作?
  14. Writing a code for speed tracking control of maglev trains in MATLAB using reinforcement learning
  15. 2021-07-11
  16. 微信小程序【网易云音乐实战】(第五篇 转发分享、每日推荐、音乐播放、页面通信npm包、进度条、全局数据)
  17. 佛说四十二章经(高丽版大藏经本)
  18. DOS命令 基础命令
  19. VIVADO eco 功能
  20. from用法 prepare_单词与短语 知识讲解 prepare,prepare for,be prepared for,be prepared from的区别...

热门文章

  1. 微型计算机接口期末,微机接口技术期末复习题及其答案 (2)
  2. java 代码里设置环境变量_如何在一个java程序里设置环境变量
  3. 大数据 挑战 机会_大数据可视化面临哪些挑战
  4. javascript class
  5. TensorFlow 保存和加载模型
  6. 2.9 logistic 回归中的梯度下降法
  7. flask request类
  8. 如何导出源文件_正骨室001期 | 如何避免色彩损失
  9. java订单类_使用Java创建一个订单类代码实例
  10. 基于VMware vSphere的虚拟化平台,内存分配是如何实现的?