学习资料在这里
对于k维KDTree,实际时间复杂度为O(N*N^(1-1/k))
build实现类似spaly,不断选一维从中间划分,可以循环选取维度,也可以rand % k
求最近点的query,重点在于其中的估价函数
求区间和的query,则和线段树类似
例题:
1)模板题
bzoj 2648求最近点
1 /*为了维持树的平衡,可以一开始把所有点都读进来build 2 然后打flag标记该点是否被激活*/ 3 #include <bits/stdc++.h> 4 5 using namespace std; 6 7 const int N = 5e5 + 5; 8 9 const int inf = 1 << 30; 10 11 int n, m; 12 13 int ql, qr, ans, tot, nowD; 14 //nowD = rand() & 1 ? 15 struct Node { 16 int d[2]; 17 18 bool operator < (const Node &a) const { 19 if (d[nowD] == a.d[nowD]) return d[!nowD] < a.d[!nowD]; 20 return d[nowD] < a.d[nowD]; 21 } 22 }pot[N]; 23 24 struct node { 25 int min[2], max[2], d[2]; 26 node *c[2]; 27 28 node() { 29 min[0] = min[1] = max[0] = max[1] = d[0] = d[1] = 0; 30 c[0] = c[1] = NULL; 31 } 32 33 node(int x, int y); 34 35 void update(); 36 37 38 }t[N], Null, *root; 39 40 node::node(int x, int y) { 41 min[0] = max[0] = d[0] = x; 42 min[1] = max[1] = d[1] = y; 43 c[0] = c[1] = &Null; 44 } 45 46 inline void node::update() { 47 if (c[0] != &Null) { 48 if (c[0] -> max[0] > max[0]) max[0] = c[0] -> max[0]; 49 if (c[0] -> max[1] > max[1]) max[1] = c[0] -> max[1]; 50 if (c[0] -> min[0] < min[0]) min[0] = c[0] -> min[0]; 51 if (c[0] -> min[1] < min[1]) min[1] = c[0] -> min[1]; 52 } 53 if (c[1] != &Null) { 54 if (c[1] -> max[0] > max[0]) max[0] = c[1] -> max[0]; 55 if (c[1] -> max[1] > max[1]) max[1] = c[1] -> max[1]; 56 if (c[1] -> min[0] < min[0]) min[0] = c[1] -> min[0]; 57 if (c[1] -> min[1] < min[1]) min[1] = c[1] -> min[1]; 58 } 59 } 60 61 inline void build(node *&o, int l, int r, int D) { 62 int mid = l + r >> 1; 63 nowD = D; 64 nth_element(pot + l, pot + mid, pot + r + 1); 65 o = new node(pot[mid].d[0], pot[mid].d[1]); 66 67 if (l != mid) build(o -> c[0], l, mid - 1, !D); 68 if (r != mid) build(o -> c[1], mid + 1, r, !D); 69 o -> update(); 70 } 71 72 inline void insert(node *o) { 73 node *p = root; 74 int D = 0; 75 while (1) { 76 if (o -> max[0] > p -> max[0]) p -> max[0] = o -> max[0]; 77 if (o -> max[1] > p -> max[1]) p -> max[1] = o -> max[1]; 78 if (o -> min[0] < p -> min[0]) p -> min[0] = o -> min[0]; 79 if (o -> min[1] < p -> min[1]) p -> min[1] = o -> min[1]; 80 81 if (o -> d[D] >= p -> d[D]) { 82 if (p -> c[1] == &Null) { 83 p -> c[1] = o; 84 return; 85 } else p = p -> c[1]; 86 } else { 87 if (p -> c[0] == &Null) { 88 p -> c[0] = o; 89 return; 90 } else p = p -> c[0]; 91 } 92 D ^= 1; 93 } 94 } 95 96 inline int dist(node *o) { 97 int dis = 0; 98 if (ql < o -> min[0]) dis += o -> min[0] - ql; 99 if (ql > o -> max[0]) dis += ql - o -> max[0]; 100 if (qr < o -> min[1]) dis += o -> min[1] - qr; 101 if (qr > o -> max[1]) dis += qr - o -> max[1]; 102 return dis; 103 } 104 105 inline void query(node *o) { 106 int dl, dr, d0; 107 d0 = abs(o -> d[0] - ql) + abs(o -> d[1] - qr); 108 if (d0 < ans) ans = d0; 109 if (o -> c[0] != &Null) dl = dist(o -> c[0]); 110 else dl = inf; 111 if (o -> c[1] != &Null) dr = dist(o -> c[1]); 112 else dr = inf; 113 114 if (dl < dr) { 115 if (dl < ans) query(o -> c[0]); 116 if (dr < ans) query(o -> c[1]); 117 } else { 118 if (dr < ans) query(o -> c[1]); 119 if (dl < ans) query(o -> c[0]); 120 } 121 } 122 123 int main() { 124 ios::sync_with_stdio(false); 125 cin >> n >> m; 126 for (int i = 1; i <= n; i ++) 127 cin >> pot[i].d[0] >> pot[i].d[1]; 128 build(root, 1, n, 0); 129 130 for (int x, y, z; m --; ) { 131 cin >> x >> y >> z; 132 if (x == 1) { 133 t[tot].max[0] = t[tot].min[0] = t[tot].d[0] = y; 134 t[tot].max[1] = t[tot].min[1] = t[tot].d[1] = z; 135 t[tot].c[0] = t[tot].c[1] = &Null; 136 insert(&t[tot ++]); 137 } else { 138 ans = inf, ql = y, qr = z; 139 query(root), printf("%d\n", ans); 140 } 141 } 142 return 0; 143 }
这题卡常数,可以不加快读,但是建议使用inline和指针
bzoj 4066 二维平面,单点修改,区间查询