一句话不说你们又不高兴
k-d Tree 可以处理 k 维空间内的最近(第二近、第三近……)邻点查询。
回忆一下二叉搜索树。
每个节点存个值,左子树节点的值都比它小,右子树节点的值都比它大。
问题扩展到 k 维空间内,每个点由一个 k 维向量表示其坐标。
如果树中节点 u 以第 d 维坐标作为分割依据,那么 u 的左子树的第 d 维坐标都比它小,右子树……
这样的树就是 k-d Tree
详情看ppt
注意他那样建树寻址的代价非常小。如果你用全局数组就会t飞2648
所以推荐大家有初始化建树的时候写结构体,否则就写数组或指针吧。结构体飞来飞去太难看了。
闷声写大题
Prob | Hint |
---|---|
2648-SJY摆棋子 | kdtree 不需要重建 |
4066-简单题 | kdtree 区域查询 需要重建 |
3053-The-Closet-M-Points | 真k dtree,不带修改 |
//2648
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cctype>
namespace I {
const int L = 1 << 15 | 1;
char *s, *t, buf[L];
inline char gc() {
if (s == t) t = (s = buf) + fread(buf, 1, L, stdin);
return *s++;
}
inline int gi() {
int ch = gc(), x = 0;
while (!isdigit(ch)) ch = gc();
while (isdigit(ch)) x = x*10 + ch -'0', ch = gc();
return x;
}
}using I::gi;
using std::max;
using std::min;
const int N = int(5e5 + 10) << 1;
const double fac = 0.7;
int n, m, D, mem, rt;
struct ND {
int d[2], mn[2], mx[2], ch[2];
bool operator<(const ND& b)const {return d[D] < b.d[D];}
inline void rd() {
d[0] = gi(), d[1] = gi();
}
}a[N];
inline void up(int o) {
for (int i = 0; i < 2; i++) {
a[o].mn[i] = a[o].mx[i] = a[o].d[i];
for (int j = 0; j < 2; j++) if (a[o].ch[j]) {
a[o].mn[i] = min(a[o].mn[i], a[a[o].ch[j]].mn[i]);
a[o].mx[i] = max(a[o].mx[i], a[a[o].ch[j]].mx[i]);
}
}
}
int build(int l, int r, int t) {
if (l > r) return 0;
int mid = l + r >> 1;
D = t;
std::nth_element(a + l, a + mid, a + r + 1);
a[mid].ch[0] = build(l, mid - 1, t^1);
a[mid].ch[1] = build(mid + 1, r, t^1);
up(mid);
return mid;
}
void in(int& o, int p, int t) {
if (!o) o = p;
else in(a[o].ch[a[p].d[t] > a[o].d[t]], p, t^1);
up(o);
}
int x, y, ans;
inline int val(int o) {
return o ? max(max(a[o].mn[0] - x, x - a[o].mx[0]), 0) + max(max(a[o].mn[1] - y, y - a[o].mx[1]), 0): 1e9;
}
void query(int o) {
if (!o) return;
ans = min(abs(a[o].d[0] - x) + abs(a[o].d[1] - y), ans);
int gd[2];
gd[0] = val(a[o].ch[0]), gd[1] = val(a[o].ch[1]);
int t = gd[1] < gd[0];
if (gd[t] < ans) query(a[o].ch[t]);
t^=1;
if (gd[t] < ans) query(a[o].ch[t]);
}
int main() {
n = gi(), m = gi();
for (int i = 1; i <= n; i++) {
a[++mem].rd();
up(i);
}
rt = build(1, mem, 0);
while (m--) {
int t = gi();
x = gi(), y = gi();
if (t == 1) {
++mem;
a[mem].d[0] = x, a[mem].d[1] = y;
up(mem);
in(rt, mem, 0);
}
else if (t == 2) {
ans = 1e9;
query(rt);
printf("%d\n", ans);
}
}
}
//4066
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
const double fac = 0.7;
int n, m, D, ans, sz;
struct ND{
int d[2], l[2], r[2], sz, w, s;
ND* ch[2];
ND(int x, int y, int v) {d[0] = x, d[1] = y, w = v;up();}
inline void up() {
l[0] = r[0] = d[0];
l[1] = r[1] = d[1];
s = w;
sz = 1;
for (int j = 0; j < 2; j++) if (ch[j]) {
s += ch[j]->s;
sz += ch[j]->sz;
for (int i = 0; i < 2; i++)
l[i] = std::min(l[i], ch[j]->l[i]),
r[i] = std::max(r[i], ch[j]->r[i]);
}
}
}*rt;
bool cmp(ND* a, ND* b) {
return a->d[D] < b->d[D];
}
ND* po[int(5e5 + 1) << 2];
ND* build(int l, int r, int d) {
if (l > r) return 0;
D = d;
int mid = l + r >> 1;
std::nth_element(po + l, po + mid, po + r + 1, cmp);
ND* p = po[mid];
p->ch[0] = build(l, mid - 1, d^1);
p->ch[1] = build(mid + 1, r, d^1);
p->up();
return p;
}
void dfs(ND* u) {
if (!u) return;
dfs(u->ch[0]);
po[++sz] = u;
dfs(u->ch[1]);
}
void rebuild(ND*& u, int d) {
sz = 0;
dfs(u);
u = build(1, sz, d);
}
void in(ND*& o, ND* p, int d) {
if (!o) o = p;
else in(o->ch[p->d[d] >= o->d[d]], p, d^1);
o->up();
int s = 0;
for (int i = 0; i < 2; i++) if (o->ch[i]) s = std::max(s, o->ch[i]->sz);
if (s > o->sz*fac) rebuild(o, d);
}
int x0, x1, y0, y1;
int query(ND* o) {
if (!o || o->l[0] > x1 || o->r[0] < x0 || o->l[1] > y1 || o->r[1] < y0) return 0;
if (x0 <= o->l[0] && o->r[0] <= x1 &&
y0 <= o->l[1] && o->r[1] <= y1) return o->s;
int s = 0;
if (x0 <= o->d[0] && o->d[0] <= x1 &&
y0 <= o->d[1] && o->d[1] <= y1) s += o->w;
return s + query(o->ch[0]) + query(o->ch[1]);
}
int main() {
// freopen("input", "r", stdin);
// freopen("bzoj_4066.in", "r", stdin);
// freopen("bzoj_4066.out", "w", stdout);
scanf("%d", &n);
while (1) {
int t;
scanf("%d", &t);
if (t == 1) {
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
x^=ans, y^=ans, w^=ans;
ND* p = new ND(x, y, w);
in(rt, p, 0);
}
else if (t == 2) {
scanf("%d%d%d%d", &x0, &y0, &x1, &y1);
x0 ^= ans, x1^=ans, y0^=ans,y1^=ans;
printf("%d\n", ans = query(rt));
}
else break;
}
}
//3053
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cassert>
#define nxd ((d + 1)%k)
using std::min;
using std::max;
const int N = 5e4 + 10, K = 5, M = 15, INF = 2e9 + 1;
int n, D, k, m, ans[M];
struct P{
int d[K], mn[K], mx[K], ch[2];
bool operator<(const P& b)const {return d[D] < b.d[D];}
inline void rd() {
for (int i = 0; i < k; i++) scanf("%d", &d[i]);
}
}a[N];
inline void up(int o) {
for (int i = 0; i < k; i++) a[o].mn[i] = a[o].mx[i] = a[o].d[i];
for (int i = 0; i < 2; i++) if (a[o].ch[i])
for (int j = 0; j < k; j++) a[o].mn[j] = min(a[o].mn[j], a[a[o].ch[i]].mn[j]), a[o].mx[j] = max(a[o].mx[j], a[a[o].ch[i]].mx[j]);
}
inline int sq(int x) {return x*x;}
inline int dis(int x, int y) {
if (!x || !y) return INF;
int s = 0;
for (int i = 0; i < k; i++) s += sq(a[x].d[i] - a[y].d[i]);
return s;
}
int build(int l, int r, int d) {
if (l > r) return 0;
int mid = l + r >> 1;
D = d;
std::nth_element(a + l, a + mid, a + r + 1);
a[mid].ch[0] = build(l, mid - 1, nxd);
a[mid].ch[1] = build(mid + 1, r, nxd);
up(mid);
return mid;
}
int acnt;
inline void addans(int o) {
int dd = dis(o, n + 1);
for (int i = 1; i <= min(acnt + 1, m); i++) if (dd < dis(ans[i], n + 1)) {
for (int j = acnt; j > i; j--) ans[j] = ans[j - 1];
ans[i] = o;
acnt = min(acnt + 1, m);
break;
}
// for (int i = 1; i < acnt; i++) assert(dis(ans[i], n + 1) < dis(ans[i + 1], n + 1));
}
inline int val(int o) {
if (o) {
int s = 0;
for (int i = 0, c = n + 1; i < k; i++) s += sq(max(max(a[o].mn[i] - a[c].d[i], a[c].d[i] - a[o].mx[i]), 0));
return s;
}
else return INF;
}
void query(int o) {
if (!o) return;
addans(o);
int gd[2];
gd[0] = val(a[o].ch[0]), gd[1] = val(a[o].ch[1]);
int t = gd[1] < gd[0], dd = dis(ans[m], n + 1);
if (dd >= gd[t]) query(a[o].ch[t]);
t ^= 1;
dd = dis(ans[m], n + 1);
if (dd >= gd[t]) query(a[o].ch[t]);
}
int rt;
void solve() {
for (int i = 1; i <= n; i++) a[i].rd(), up(i);
rt = build(1, n, 0);
int q;
scanf("%d", &q);
while (q--) {
for (int i = 0; i < k; i++) scanf("%d", &a[n + 1].d[i]);
scanf("%d", &m);
memset(ans, 0, sizeof(ans));
acnt = 0;
query(rt);
printf("the closest %d points are:\n", m);
for (int i = 1; i <= m; i++) {
for (int j = 0; j < k; j++) printf("%d", a[ans[i]].d[j]), j == k - 1 ? 0: putchar(' ');
putchar('\n');
}
}
}
int main() {
//freopen("input", "r", stdin);
while (scanf("%d%d", &n, &k) == 2) solve();
}