[笔记] K-D Tree
一种可以 高效处理 \(k\) 维空间信息 的数据结构。
在正确使用的情况下,复杂度为 \(O(n^{1-\frac{1}{k}})\).
K-D Tree 的实现
建树
随机一维选择最中间的点为当前子树的根,每个节点维护当前点的坐标,已经整个子树的矩形坐标。
Pink Rabbit 说随机选维度没什么问题。
int rt, ID;
struct node{ int lc, rc, x[K], L[K], R[K]; } t[N];
inline bool cmp(const node &a, const node &b){ return a.x[ID] < b.x[ID]; }
inline void getedge(int x){
lfo(i, 0, K) t[x].L[i] = t[x].R[i] = t[x].x[i];
if(ls(x)) lfo(i, 0, K) Min(t[x].L[i], t[ls(x)].L[i]), Max(t[x].R[i], t[ls(x)].R[i]);
if(rs(x)) lfo(i, 0, K) Min(t[x].L[i], t[rs(x)].L[i]), Max(t[x].R[i], t[rs(x)].R[i]);
}
void build(int &x, int l, int r){
if(l > r) return;
int mid = l + r >> 1; x = mid, ID = rand() % K;
nth_element(t + l, t + mid, t + r + 1, cmp);
build(ls(x), l, mid - 1), build(rs(x), mid + 1, r);
getedge(x);
}
插入/删除
- 删除比较简单,直接标记为不存在即可,复杂度依然靠谱。
- 插入比较麻烦,如果可离线的话,最好先建树,否则考虑 \(\sqrt n\) 次插入操作后重构整棵树。
复杂度分析
在递归过程中,判断是否继续是:
- 相交:继续
- 包含:打标记,return
- 相离:return
则复杂度最优 \(O(\log n)\),最劣 \(O(n^{1-\frac{1}{k}})\)。
K-D Tree 的应用
-
求最近点对的骗分做法。
-
范围修改/查询问题:矩形覆盖,多维偏序……