KD-Tree的思想其实很简单,就是将点对依次按照横坐标、纵坐标、横坐标、纵坐标……分治,维护一些信息用于启发式搜索。貌似求最近点对的复杂度没什么保证,但确实非常快…
一般而言几种情况:
最近曼哈顿距离,维护 xmin,xmax,ymin,ymax ,则 (x,y) 的启发函数是 max(xmin−x,0)+max(x−xmax,0)+max(ymin−y,0)+max(y−ymax,0)
最远曼哈顿距离,维护 xmin,xmax,ymin,ymax ,则 (x,y) 启发函数是 max(|xmin−x|,|xmax−x|)+max(|ymin−y|,|ymax−y|)
最近欧几里得距离/最远欧几里得距离,都加个平方即可。
曼哈顿距离kdtree模板题…
#include
using namespace std;
const int MAXN = 500005;
struct point {
int x, y;
inline void update_max(const point &a)
{ x = max(x, a.x), y = max(y, a.y); }
inline void update_min(const point &a)
{ x = min(x, a.x), y = min(y, a.y); }
} pts[MAXN];
inline bool cmpx(const point &a, const point &b)
{ return a.x < b.x; }
inline bool cmpy(const point &a, const point &b)
{ return a.y < b.y; }
struct node {
point pt, pt_min, pt_max;
int lc, rc;
int split_mod;
inline void update();
inline int h_max(const point &a);
inline int h_min(const point &a);
inline int trans(const point &a);
} kdtree[MAXN];
int top = 0, root;
inline void node::update()
{
if (lc) pt_min.update_min(kdtree[lc].pt_min), pt_max.update_max(kdtree[lc].pt_max);
if (rc) pt_min.update_min(kdtree[rc].pt_min), pt_max.update_max(kdtree[rc].pt_max);
}
inline int node::h_max(const point &a)
{ return max(abs(a.x-pt_min.x), abs(a.x-pt_max.x))+max(abs(a.y-pt_min.y), abs(a.y-pt_max.y)); }
inline int node::h_min(const point &a)
{ return max(a.x-pt_max.x, 0)+max(pt_min.x-a.x, 0)+max(a.y-pt_max.y, 0)+max(pt_min.y-a.y, 0); }
inline int dis(int i, int j)
{ return abs(kdtree[i].pt.x-kdtree[j].pt.x)+abs(kdtree[i].pt.y-kdtree[j].pt.y); }
inline int node::trans(const point &a)
{
if (split_mod == 0) return a.x <= pt.x;
else return a.y <= pt.y;
}
void build(int &nd, int L, int R, int split_mod = 0)
{
if (L > R) return;
nd = ++top;
int mid = (L+R)>>1;
if (split_mod == 0) nth_element(pts+L, pts+mid, pts+R+1, cmpx);
else nth_element(pts+L, pts+mid, pts+R+1, cmpy);
kdtree[nd].pt = kdtree[nd].pt_min = kdtree[nd].pt_max = pts[mid];
build(kdtree[nd].lc, L, mid-1, split_mod^1), build(kdtree[nd].rc, mid+1, R, split_mod^1);
kdtree[nd].update();
}
int ans, n;
void query_min(int nd, const int pos)
{
if (pos != nd) ans = min(ans, dis(nd, pos));
int l = kdtree[nd].lc?kdtree[kdtree[nd].lc].h_min(kdtree[pos].pt):0, r = kdtree[nd].rc?kdtree[kdtree[nd].rc].h_min(kdtree[pos].pt):0;
if (l < r) {
if (kdtree[nd].lc && l < ans) query_min(kdtree[nd].lc, pos);
if (kdtree[nd].rc && r < ans) query_min(kdtree[nd].rc, pos);
} else {
if (kdtree[nd].rc && r < ans) query_min(kdtree[nd].rc, pos);
if (kdtree[nd].lc && l < ans) query_min(kdtree[nd].lc, pos);
}
}
void query_max(int nd, const int pos)
{
if (pos != nd) ans = max(ans, dis(nd, pos));
int l = kdtree[nd].lc?kdtree[kdtree[nd].lc].h_max(kdtree[pos].pt):0, r = kdtree[nd].rc?kdtree[kdtree[nd].rc].h_max(kdtree[pos].pt):0;
if (l > r) {
if (kdtree[nd].lc && l > ans) query_max(kdtree[nd].lc, pos);
if (kdtree[nd].rc && r > ans) query_max(kdtree[nd].rc, pos);
} else {
if (kdtree[nd].rc && r > ans) query_max(kdtree[nd].rc, pos);
if (kdtree[nd].lc && l > ans) query_max(kdtree[nd].lc, pos);
}
}
int qmax(int pos)
{
ans = 0;
query_max(root, pos);
return ans;
}
int qmin(int pos)
{
ans = 1e9;
query_min(root, pos);
return ans;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &pts[i].x, &pts[i].y);
build(root, 1, n);
int A = 1e9;
for (int i = 1; i <= n; i++) {
A = min(A, qmax(i)-qmin(i));
}
printf("%d\n", A);
return 0;
}
用一个堆优化静态kd-tree。如果当前距离比堆中最小的距离大,则更新;如果最大可能的距离比堆中距离小,则不再向下递归。
#include
using namespace std;
const int MAXN = 100050;
struct point {
long long x, y;
inline void max_update(const point &a)
{ x = max(x, a.x), y = max(y, a.y); }
inline void min_update(const point &a)
{ x = min(x, a.x), y = min(y, a.y); }
} pts[MAXN];
int n, root;
inline bool cmpx(const point &a, const point &b)
{ return a.x < b.x; }
inline bool cmpy(const point &a, const point &b)
{ return a.y < b.y; }
struct node {
int lc, rc;
point pt;
point min_pt, max_pt;
int split_mod;
void update();
long long h(const point &pt);
} kdtree[MAXN];
int top = 0;
void node::update()
{
min_pt = max_pt = pt;
if (lc) min_pt.min_update(kdtree[lc].min_pt), max_pt.max_update(kdtree[lc].max_pt);
if (rc) min_pt.min_update(kdtree[rc].min_pt), max_pt.max_update(kdtree[rc].max_pt);
}
inline long long sqr_pow(long long nd)
{ return nd*nd; }
inline long long dis(int i, int j)
{ return sqr_pow(kdtree[i].pt.x-kdtree[j].pt.x)+sqr_pow(kdtree[i].pt.y-kdtree[j].pt.y); }
long long node::h(const point &pt)
{
return max(sqr_pow(pt.x-min_pt.x), sqr_pow(pt.x-max_pt.x))+max(sqr_pow(pt.y-min_pt.y), sqr_pow(pt.y-max_pt.y));
}
void build(int &nd, int L, int R, int now_split = 0)
{
if (L > R) return;
nd = ++top;
int mid = (L+R)>>1;
nth_element(pts+L, pts+mid, pts+R+1, now_split==0?cmpx:cmpy);
kdtree[nd].pt = kdtree[nd].min_pt = kdtree[nd].max_pt = pts[mid];
if (L < R) {
build(kdtree[nd].lc, L, mid-1, now_split^1), build(kdtree[nd].rc, mid+1, R, now_split^1);
kdtree[nd].update();
}
}
priority_queue<long long, vector<long long>, greater<long long> > q;
void query(int nd, int pos)
{
long long d = dis(nd, pos);
if (d > q.top()) q.pop(), q.push(d);
long long L = kdtree[nd].lc?kdtree[kdtree[nd].lc].h(kdtree[pos].pt):0, R = kdtree[nd].rc?kdtree[kdtree[nd].rc].h(kdtree[pos].pt):0;
if (L > R) {
if (kdtree[nd].lc && L > q.top()) query(kdtree[nd].lc, pos);
if (kdtree[nd].rc && R > q.top()) query(kdtree[nd].rc, pos);
} else {
if (kdtree[nd].rc && R > q.top()) query(kdtree[nd].rc, pos);
if (kdtree[nd].lc && L > q.top()) query(kdtree[nd].lc, pos);
}
}
int k;
int main()
{
scanf("%d%d", &n, &k);
k *= 2;
for (int i = 1; i <= n; i++)
scanf("%lld%lld", &pts[i].x, &pts[i].y);
build(root, 1, n);
for (int i = 1; i <= k; i++) q.push(0);
for (int i = 1; i <= n; i++)
query(root, i);
printf("%lld\n", q.top());
return 0;
}
kdtree动态插入..
#include
using namespace std;
const int MAXN = 1000005;
struct point {
int x, y;
inline void update_min(const point &a)
{ x = min(x, a.x), y = min(y, a.y); }
inline void update_max(const point &a)
{ x = max(x, a.x), y = max(y, a.y); }
friend bool operator == (const point &a, const point &b)
{ return a.x==b.x && a.y==b.y; }
friend int operator * (const point &a, const point &b)
{ return abs(a.x-b.x)+abs(a.y-b.y); }
} pts[MAXN];
int pts_top = 0;
struct node {
int lc, rc;
point pt, min_pt, max_pt;
int split_mod;
inline void update();
inline int h(const point &pt);
} kdtree[MAXN];
int top = 0, root = 0;
inline void node::update()
{
if (lc) min_pt.update_min(kdtree[lc].min_pt), max_pt.update_max(kdtree[lc].max_pt);
if (rc) min_pt.update_min(kdtree[rc].min_pt), max_pt.update_max(kdtree[rc].max_pt);
}
inline int node::h(const point &pt)
{ return max(min_pt.x-pt.x, 0)+max(pt.x-max_pt.x, 0)+max(min_pt.y-pt.y, 0)+max(pt.y-max_pt.y, 0); }
void push(int &nd, const point &pt, int split_mod = 0)
{
if (!nd) nd = ++top, kdtree[nd] = (node){0, 0, pt, pt, pt, split_mod};
else if (kdtree[nd].pt == pt) return;
else {
if (split_mod == 0) push(pt.x<=kdtree[nd].pt.x?kdtree[nd].lc:kdtree[nd].rc, pt, split_mod^1);
else push(pt.y<=kdtree[nd].pt.y?kdtree[nd].lc:kdtree[nd].rc, pt, split_mod^1);
kdtree[nd].update();
}
}
int ans = 0;
void query(int nd, const point &pt)
{
ans = min(ans, kdtree[nd].pt*pt);
int L = kdtree[nd].lc?kdtree[kdtree[nd].lc].h(pt):0, R = kdtree[nd].rc?kdtree[kdtree[nd].rc].h(pt):0;
if (L < R) {
if (kdtree[nd].lc && L < ans) query(kdtree[nd].lc, pt);
if (kdtree[nd].rc && R < ans) query(kdtree[nd].rc, pt);
} else {
if (kdtree[nd].rc && R < ans) query(kdtree[nd].rc, pt);
if (kdtree[nd].lc && L < ans) query(kdtree[nd].lc, pt);
}
}
inline int mindis(const point &pt)
{ return ans = INT_MAX, query(root, pt), ans; }
inline bool cmpx(const point &a, const point &b)
{ return a.x < b.x; }
inline bool cmpy(const point &a, const point &b)
{ return a.y < b.y; }
int get_split_mod(int L, int R)
{
double avex = 0, avey = 0, sqx = 0, sqy = 0;
for (register int i = L; i <= R; i++)
avex += pts[i].x, avey += pts[i].y;
avex /= R-L+1, avey /= R-L+1;
for (register int i = L; i <= R; i++)
sqx += (pts[i].x-avex)*(pts[i].x-avex), sqy += (pts[i].y-avey)*(pts[i].y-avey);
return sqx <= sqy;
}
void build(int &nd, int L, int R, int split_mod = 0)
{
if (L > R) return;
nd = ++top;
int mid = (L+R)>>1;
kdtree[nd].split_mod = split_mod;
nth_element(pts+L, pts+mid, pts+R+1, kdtree[nd].split_mod?cmpy:cmpx);
kdtree[nd].pt = kdtree[nd].min_pt = kdtree[nd].max_pt = pts[mid];
kdtree[nd].lc = kdtree[nd].rc = 0;
build(kdtree[nd].lc, L, mid-1, split_mod^1), build(kdtree[nd].rc, mid+1, R, split_mod^1);
kdtree[nd].update();
}
inline void reconstruct()
{ top = 0, root = 0, build(root, 1, pts_top); }
int n, m, tp;
int x, y;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &x, &y);
pts[++pts_top] = (point){x, y};
}
reconstruct();
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &tp, &x, &y);
if (tp == 1) pts[++pts_top] = (point){x, y}, push(root, (point){x, y});
else printf("%d\n", mindis((point){x, y}));
}
return 0;
}