BZOJ2716 天使玩偶

之前写过CDQ + 线段树的, 被惨烈地卡常卡了下来...
所以决定改写KD-tree
这里先放个代码占个坑, 后面再写教程吧.

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <climits>
#include <cmath>
  
namespace Zeonfai
{
    inline int getInt()
    {
        int a = 0, sgn = 1;
        char c;
  
        while(! isdigit(c = getchar()))
            if(c == '-')
                sgn *= -1;
  
        while(isdigit(c))
            a = a * 10 + c - '0', c = getchar();
  
        return a * sgn;
    }
  
    inline void _print(int a)
    {
        if(! a)
            return;
  
        _print(a / 10);
        putchar('0' + a % 10);
    }
  
    inline void println(int a)
    {
        if(a < 0)
            putchar('-'), a *= -1;
  
        if(! a)
            putchar('0');
  
        _print(a);
        putchar('\n');
    }
}
  
const int N = (int)5e5, M = (int)5e5;
int n, m;
int dmn;
  
struct point
{
    int x, y;
      
    inline point() {}
  
    inline point(int _x, int _y)
    {
        x = _x, y = _y;
    }
  
    inline int friend operator <(const point &a, const point &b)
    {
        if(dmn == 0)
            return a.x < b.x;
        else
            return a.y < b.y;
    }
};
  
point pos[N + M];
  
struct KDtree
{
    struct node
    {
        node *suc[2];
        point p, bnd[2];
  
        inline node(const point &_p)
        {
            bnd[0] = bnd[1] = p = _p, suc[0] = suc[1] = NULL;
        }
  
        inline void update()
        {
            bnd[0] = bnd[1] = p;
  
            for(int i = 0; i < 2; ++ i)
                if(suc[i] != NULL)
                {
                    bnd[0].x = std::min(suc[i]->bnd[0].x, bnd[0].x), bnd[0].y = std::min(suc[i]->bnd[0].y, bnd[0].y);
                    bnd[1].x = std::max(suc[i]->bnd[1].x, bnd[1].x), bnd[1].y = std::max(suc[i]->bnd[1].y, bnd[1].y);
                }
        }
    };
  
    node *rt;
  
    node* build(int L, int R, int D)
    {
        if(L > R)
            return NULL;
  
        int mid = L + R >> 1;
        dmn = D;
        std::nth_element(pos + L, pos + mid, pos + R + 1);
        node *u = new node(pos[mid]);
        u->suc[0] = build(L, mid - 1, D ^ 1);
        u->suc[1] = build(mid + 1, R, D ^ 1);
        u->update();
        return u;
    }
  
    inline void build()
    {
        rt = build(0, n - 1, 0);
    }
  
    node* insert(node *u, const point &p, int D)
    {
        if(u == NULL)
        {
            u = new node(p);
            return u;
        }
  
        dmn = D;
          
        if(p < u->p)
            u->suc[0] = insert(u->suc[0], p, D ^ 1);
        else
            u->suc[1] = insert(u->suc[1], p, D ^ 1);
  
        u->update();
        return u;
    }
  
    inline void insert(const point &p)
    {
        rt = insert(rt, p, 0);
    }
  
    int ans;
  
    inline int getDistance(const point &a, const point &b)
    {
        return abs(a.x - b.x) + abs(a.y - b.y);
    }
  
    inline int getDistance(const point &p, node *u)
    {
        if(u == NULL)
            return INT_MAX;
  
        int res = 0;
  
        if(p.x < u->bnd[0].x || p.x > u->bnd[1].x)
            res += p.x < u->bnd[0].x ? u->bnd[0].x - p.x : p.x - u->bnd[1].x;
  
        if(p.y < u->bnd[0].y || p.y > u->bnd[1].y)
            res += p.y < u->bnd[0].y ? u->bnd[0].y - p.y : p.y - u->bnd[1].y;
  
        return res;
    }
  
    void query(node *u, const point &p)
    {
        if(u == NULL)
            return;
  
        ans = std::min(ans, getDistance(p, u->p));
        int k = getDistance(p, u->suc[0]) > getDistance(p, u->suc[1]);
  
        if(getDistance(p, u->suc[k]) < ans)
            query(u->suc[k], p);
  
        if(getDistance(p, u->suc[k ^ 1]) < ans)
            query(u->suc[k ^ 1], p);
    }
  
    inline int query(const point &p)
    {
        ans = INT_MAX;
        query(rt, p);
        return ans;
    }
}KDT;
  
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("BZOJ2716.in", "r", stdin);
    freopen("BZOJ2716KDT.out", "w", stdout);
    #endif
  
    using namespace Zeonfai;
  
    n = getInt(), m = getInt();
  
    for(int i = 0; i < n; ++ i)
        pos[i].x = getInt(), pos[i].y = getInt();
  
    KDT.build();
  
    while(m --)
    {
        int tp = getInt(), x = getInt(), y = getInt();
  
        if(tp == 1)
            KDT.insert(pos[n ++] = point(x, y));
        else
            println(KDT.query(point(x, y)));
    }
}
posted @ 2017-05-28 21:38  Zeonfai  阅读(242)  评论(0编辑  收藏  举报