KD-Tree解决空间最短距离的利器

来源:互联网 发布:重庆交通大学网络教育 编辑:程序博客网 时间:2024/06/15 00:12

KD-Tree解决空间最短距离的利器

本文作者:Caozhijie

/**************************************************************    Problem: 2648    User: Cardinal    Language: C++    Result: Accepted    Time:14476 ms    Memory:40356 kb****************************************************************/#include <cstdio>#include <cstring>#include <climits>#include <iostream>#include <algorithm>using namespace std;#define Min(a, b) ((a)<(b)?(a):(b))#define Max(a, b) ((a)>(b)?(a):(b))#define Abs(x) ((x)>0?(x):-(x))#define N 500010#define M 500010int n, m;struct Point {    int x, y;    Point(int _x = 0, int _y = 0):x(_x),y(_y){}    void set(int _, int __) {        x = _, y = __;    }}P[N + M];int Dis(const Point &A, const Point &B) {    return Abs(A.x - B.x) + Abs(A.y - B.y);}bool sign;inline bool cmp(const Point &A, const Point &B) {    if (sign)        return A.x < B.x || (A.x == B.x && A.y < B.y);    else        return A.y < B.y || (A.y == B.y && A.x < B.x);}struct Node {    Node *l, *r;    int x[2], y[2];    Point p;    void SetP(const Point &P) {        p = P;        x[0] = x[1] = P.x;        y[0] = y[1] = P.y;    }    int Dis(const Point &p) const {        int res = 0;        if (p.x < x[0] || p.x > x[1])            res += (p.x < x[0]) ? x[0] - p.x : p.x - x[1];        if (p.y < y[0] || p.y > y[1])            res += (p.y < y[0]) ? y[0] - p.y : p.y - y[1];        return res;    }    void up(Node *B) {        x[0] = Min(x[0], B->x[0]);        x[1] = Max(x[1], B->x[1]);        y[0] = Min(y[0], B->y[0]);        y[1] = Max(y[1], B->y[1]);    }}mem[N + M], *C = mem, Tnull, *null = &Tnull;Node *Build(int tl, int tr, bool d) {    if (tl > tr)        return null;    int mid = (tl + tr) >> 1;    sign = d;    std::nth_element(P + tl + 1, P + mid + 1, P + tr + 1, cmp);    Node *q = C++;    q->SetP(P[mid]);    q->l = Build(tl, mid - 1, d ^ 1);    q->r = Build(mid + 1, tr, d ^ 1);    if (q->l != null)        q->up(q->l);    if (q->r != null)        q->up(q->r);    return q;}#define INF 0x3f3f3f3fint res;void Ask(Node *q, const Point &p) {    res = Min(res, Dis(q->p, p));    int DisL = q->l != null ? q->l->Dis(p) : INF;    int DisR = q->r != null ? q->r->Dis(p) : INF;    if (DisL < DisR) {        if (q->l != null)            Ask(q->l, p);        if (DisR < res && q->r != null)            Ask(q->r, p);    }    else {        if (q->r != null)            Ask(q->r, p);        if (DisL < res && q->l != null)            Ask(q->l, p);    }}void Insert(Node *root, const Point &p) {    Node *q = C++;    q->l = q->r = null;    q->SetP(p);    sign = 0;    while(1) {        root->up(q);        if (cmp(q->p, root->p)) {            if (root->l == null) {                root->l = q;                break;            }            else                root = root->l;        }        else {            if (root->r == null) {                root->r = q;                break;            }            else                root = root->r;        }        sign ^= 1;    }}int main() {    #ifndef ONLINE_JUDGE    //freopen("tt.in", "r", stdin);    //freopen("tt.out", "w", stdout);    #endif    scanf("%d%d", &n, &m);    register int i;    int ope, x, y;    for(i = 1; i <= n; ++i) {        scanf("%d%d", &x, &y);        P[i] = Point(x, y);    }    Node* root = Build(1, n, 0);    while(m--) {        scanf("%d%d%d", &ope, &x, &y);        if (ope == 1)            Insert(root, Point(x, y));        else {            res = INF;            Ask(root, Point(x, y));            printf("%d\n", res);        }    }    return 0;}