KD Tree学习笔记

KD Tree学习笔记

KD Tree 是一种用于多维数点的数据结构(一般是二维)。它并不特别复杂,本质其实很暴力,和替罪羊树与线段树都比较类似。
大致思路:每次把点分为尽可能平衡的两半,然后通过类似线段树的方式拆分查询区间,以此控制复杂度。

算法流程

构建:
如果已经给定了一些元素(k维),构建kdtree采用以下的方式:
首先,将当前区间按照第d维的中间数左右分段。d每分一层便换到下一个维度,直观理解就是:每次将这些点转个方向切一刀,切得不平衡(点大量集中在刀口上)的概率便会小一些。

这里需要用到stl里的nth_element函数,用法如下:

int mid = (l + r) >> 1; 
nth_element(a + l, a + mid, a + r + 1, cmp); 

其中cmp为比较函数。

这个函数的作用是将第 m i d mid mid个位置上放上按照cmp排好序的第 m i d mid mid字符,同时保证 m i d mid mid左边的数都比它小,右边的都比它大(等于的情况会随机分布,不需要考虑)。这个函数完美满足了我们的要求,因为我们其实不需要将它完全排好序,只要将元素按照d维下的坐标切成两段即可。
然后将 m i d mid mid位置上的元素填入树中,最后左右区间递归构建。

插入:
B S T BST BST一样,从根向下比较,一直落到叶子节点为止。
但是!如果事情这么简单就好了。
就像 B S T BST BST一旦有插入就势必会带来不平衡一样, k d t r e e kdtree kdtree也一样。碰到毒瘤出题人很容易被卡到n方。这时我们就要使用替罪羊树的重构法,遇到太不平衡的节点就将整颗子树暴力重构。这里并不太难,如果没学过替罪羊树可以查阅相关资料或者参考代码。

查询:
较为灵活,随机应变。
大致思路是,如果区间中可能存在对答案有贡献的元素就查询下去。

删除:
从没用过

复杂度:
随机 n l o g n nlogn nlogn
但是构建数据可以被卡成 n s q r t ( n ) nsqrt(n) nsqrt(n)

例题:

【模板】三维偏序
【国家集训队】JZPFAR
【CQOI2016】K远点对
简单题
【CH弱省胡策R2】TATT

细节真的很多,注意以下几点:

  • 注意重构时要用的size不是子树值的和而是子树点数和(洛谷上二十发二十分就是我)
  • 注意下标01一定不能弄错
  • 注意判断条件
  • 注意如果需要通过对某一维排序进行降维,一定要先建树后排序
  • 注意一些其他的问题

全是血淋淋的教训啊
这里给出简单题一题的代码。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std; 

const int N = 200005; 
const double P = 0.75; 

int read() 
{
   
    int q = 0, w = 1; 
	char ch = 'p'; 
    while(ch != '-'&& (ch < '0' || ch > '9')) ch = getchar(); 
    if(ch == '-') w = -1, ch = getchar(); 
    while(ch >= '0' && ch <=
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值