[模版] 带部分重构的KD_Tree

RT , 从黄学长那里初步学习到写KD树的姿势后自己摸索着写了指针+替罪羊版的,效率还可以….能够忍受。

BZOJ 4066 简单题

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>

#define rep(i, x, y) for (int i = (x), _ = (y); i <= _; ++i)
#define down(i, x, y) for (int i = (x), _ = (y); i >= _; --i)
#define x first
#define y second

using namespace std;
typedef long long LL;

template<typename T> inline void up_max(T & x, T y) { x < y ? x = y : 0; }
template<typename T> inline void up_min(T & x, T y) { x > y ? x = y : 0; }

template<typename T>
inline void read(T & x)
{
    char c;
    while ((c = getchar()) < '0' || c > '9') ;
    for (x = c - '0'; (c = getchar()) >= '0' && c <= '9'; x = x * 10 + c - '0');
}

const int N = 2e5 + 10;

namespace KD_Tree
{
    struct node
    {
        node *ch[2];
        int d[2], mx[2], my[2], size, val;
        LL sum;

        inline void push_up()
        {
            sum = val, size = 1;
            rep (i, 0, 1) if (ch[i])
            {
                sum += ch[i]->sum, size += ch[i]->size;
                up_min(mx[0], ch[i]->mx[0]);
                up_max(mx[1], ch[i]->mx[1]);
                up_min(my[0], ch[i]->my[0]);
                up_max(my[1], ch[i]->my[1]);
            }
        }
    }pool_node[N], *pool_top = pool_node;

    node *del_pool[N], **del_top = del_pool;

    inline node * newnode()
    {
        return del_top == del_pool ? ++pool_top : *(del_top--);
    }

    bool cmp_D;

    struct Point
    {
        int d[2], val;

        inline bool operator < (const Point & b) const
        {
            return d[cmp_D] < b.d[cmp_D];
        }
    } p[N];

    int top = 0;

    node *build(int l, int r, bool f)
    {
        node *o = newnode();
        int mid = (l + r) >> 1;
        cmp_D = f;
        nth_element(p + l, p + mid, p + r + 1);

        o->mx[0] = o->mx[1] = o->d[0] = p[mid].d[0];
        o->my[0] = o->my[1] = o->d[1] = p[mid].d[1];
        o->val = p[mid].val;
        o->ch[0] = l < mid ? build(l, mid - 1, f ^ 1) : 0;
        o->ch[1] = mid < r ? build(mid + 1, r, f ^ 1) : 0;
        o->push_up();

        return o;
    }

    void remove(node *o)
    {
        if (o->ch[0])
            remove(o->ch[0]);
        if (o->ch[1])
            remove(o->ch[1]);

        p[++top].val = o->val;
        p[top].d[0] = o->d[0], p[top].d[1] = o->d[1];
        *(++del_top) = o;
    }

    node ** rebuild_need;
    bool rebuild_d;

    void rebuild(node ** o)
    {
        top = 0, remove(*o);
        *o = build(1, top, rebuild_d);
    }

    void insert(node *&o, int x, int y, int v, bool f)
    {
        if (!o)
        {
            o = newnode();
            o->d[0] = o->mx[0] = o->mx[1] = x;
            o->d[1] = o->my[0] = o->my[1] = y;
            o->val = o->sum = v;
        }
        else if (o->d[0] == x && o->d[1] == y)
            o->sum += v, o->val += v;
        else 
        {
            int d = !f ? o->d[0] < x : o->d[1] < y;
            insert(o->ch[d], x, y, v, f ^ 1);
            o->push_up();
            if (o->ch[d]->size * 10 >= o->size * 7)
                rebuild_need = &o, rebuild_d = f;
        }
    }

    inline bool in(int x1, int y1, int x2, int y2, int a1, int b1, int a2, int b2)
    {
        return a1 <= x1 && b1 <= y1 && x2 <= a2 && y2 <= b2;
    }
    inline bool out(int x1, int y1, int x2, int y2, int a1, int b1, int a2, int b2)
    {
        return x2 < a1 || a2 < x1 || b2 < y1 || y2 < b1;
    }

    LL query(node *o, int x1, int y1, int x2, int y2)
    {
        if (!o || out(x1, y1, x2, y2, o->mx[0], o->my[0], o->mx[1], o->my[1]))
            return 0;
        if (in(o->mx[0], o->my[0], o->mx[1], o->my[1], x1, y1, x2, y2))
            return o->sum;
        LL ret = in(o->d[0], o->d[1], o->d[0], o->d[1], x1, y1, x2, y2) ? o->val : 0;
        return ret + query(o->ch[0], x1, y1, x2, y2) + query(o->ch[1], x1, y1, x2, y2);
    }
}

int main()
{
    #ifdef LX_JUDGE
    freopen("in.txt", "r", stdin);
    #endif
    using namespace KD_Tree;

    node *root = 0;
    int opt, x1, y1, x2, y2;
    LL la = 0;

    read(opt), 
    read(opt);
    while (opt != 3)
    { 
        switch (opt)
        {
            case 1 :
                read(x1), read(y1), read(x2);
                insert(root, x1 ^ la, y1 ^ la, x2 ^ la, 0);
                if (rebuild_need)
                {
                    rebuild(rebuild_need);
                    rebuild_need = 0;
                }
                break ;
            case 2 : 
                read(x1), read(y1), read(x2), read(y2);
                la = query(root, x1 ^ la, y1 ^ la, x2 ^ la, y2 ^ la);
                printf("%lld\n", la);
                break ;
        }
        read(opt);
    }

    return 0;
}

BZOJ 4533 数据

论查询最近最远点的姿势。
(不加rebuild的版本比rebuild版快100ms…我的姿势是不是有问题啊 TAT )

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>

#define rep(i, x, y) for (int i = (x), _ = (y); i <= _; ++i)
#define down(i, x, y) for (int i = (x), _ = (y); i >= _; --i)
#define x first
#define y second

using namespace std;
typedef long long LL;

template<typename T> inline void up_max(T & x, T y) { x < y ? x = y : 0; }
template<typename T> inline void up_min(T & x, T y) { x > y ? x = y : 0; }

template<typename T>
inline void read(T & x)
{
    char c;
    while ((c = getchar()) < '0' || c > '9') ;
    for (x = c - '0'; (c = getchar()) >= '0' && c <= '9'; x = x * 10 + c - '0');
}

const int inf = 2e9;
const int N = 2e5 + 10;

namespace KD_Tree
{
    struct node
    {
        node *ch[2];
        int d[2], mx[2], my[2], size;

        inline void push_up()
        {
            size = 1;
            rep (i, 0, 1) if (ch[i])
            {
                up_min(mx[0], ch[i]->mx[0]);
                up_max(mx[1], ch[i]->mx[1]);
                up_min(my[0], ch[i]->my[0]);
                up_max(my[1], ch[i]->my[1]);
                size += ch[i]->size;
            }
        }
    }pool_node[N], *pool_top = pool_node;

    node *del_pool[N], **del_top = del_pool;

    inline node * newnode()
    {
        return del_top == del_pool ? ++pool_top : *(del_top--);
    }

    typedef pair<int, int > Point;

    inline bool cmp_x(const Point & a, const Point & b) { return a.x < b.x; }
    inline bool cmp_y(const Point & a, const Point & b) { return a.y < b.y; }

    node **rebuild_need;
    int rebuild_d;

    Point stk[N];
    int point_cnt;

    node * build(int l, int r, bool f)
    {
        int mid = (l + r) >> 1;
        node *o = newnode();
        nth_element(stk + l, stk + mid, stk + r + 1, !f ? cmp_x : cmp_y);

        o->d[0] = o->mx[0] = o->mx[1] = stk[mid].x;
        o->d[1] = o->my[0] = o->my[1] = stk[mid].y;
        o->ch[0] = l < mid ? build(l, mid - 1, f ^ 1) : 0;
        o->ch[1] = mid < r ? build(mid + 1, r, f ^ 1) : 0;
        o->push_up();

        return o;
    }

    void remove(node *o)
    {
        if (o->ch[0])
            remove(o->ch[0]);
        if (o->ch[1])
            remove(o->ch[1]);
        stk[++point_cnt] = Point(o->d[0], o->d[1]);
        *(++del_top) = o;
    }

    void rebuild()
    {
        point_cnt = 0;
        remove(*rebuild_need);
        *rebuild_need = build(1, point_cnt, rebuild_d);
        rebuild_need = 0;
    }

    void insert(node *&o, int x, int y, bool f)
    {
        if (!o)
        {
            o = newnode();
            o->d[0] = o->mx[0] = o->mx[1] = x;
            o->d[1] = o->my[0] = o->my[1] = y;
        }
        else if (o->d[0] != x || o->d[1] != y)
        {
            int d = !f ? o->d[0] < x : o->d[1] < y;
            insert(o->ch[d], x, y, f ^ 1);
            o->push_up();
            if (o->ch[d]->size * 10 >= o->size * 7)
                rebuild_need = &o, rebuild_d = f;
        }
    }

    Point P;
    int ans;

    int calc_mx(node *o)
    {
        int ret = 0;
        ret += max(abs(o->mx[0] - P.x), abs(o->mx[1] - P.x));
        ret += max(abs(o->my[0] - P.y), abs(o->my[1] - P.y));
        return ret;
    }
    int calc_mn(node *o)
    {
        int ret = 0;
        ret += max(P.x - o->mx[1], 0) + max(o->mx[0] - P.x, 0);
        ret += max(P.y - o->my[1], 0) + max(o->my[0] - P.y, 0);
        return ret;
    }

    void Query_Max(node *o)
    {
        up_max(ans, abs(o->d[0] - P.x) + abs(o->d[1] - P.y));
        int dl = o->ch[0] ? calc_mx(o->ch[0]) : -inf;
        int dr = o->ch[1] ? calc_mx(o->ch[1]) : -inf;
        if (dl > dr)
        {
            if (dl > ans)
                Query_Max(o->ch[0]);
            if (dr > ans)
                Query_Max(o->ch[1]);
        }
        else
        {
            if (dr > ans)
                Query_Max(o->ch[1]);
            if (dl > ans)
                Query_Max(o->ch[0]);
        }
    }
    void Query_Min(node *o)
    {
        up_min(ans, abs(o->d[0] - P.x) + abs(o->d[1] - P.y));
        int dl = o->ch[0] ? calc_mn(o->ch[0]) : inf;
        int dr = o->ch[1] ? calc_mn(o->ch[1]) : inf;
        if (dl < dr)
        {
            if (dl < ans)
                Query_Min(o->ch[0]);
            if (dr < ans)
                Query_Min(o->ch[1]);
        }
        else
        {
            if (dr < ans)
                Query_Min(o->ch[1]);
            if (dl < ans)
                Query_Min(o->ch[0]);
        }
    }

    node *root;

    int Query(int x, int y, bool f)
    {
        P = Point(x, y);
        if (f)
            ans = -inf, Query_Max(root);
        else 
            ans = inf, Query_Min(root);
        return ans;
    }
}

int main()
{
    #ifdef LX_JUDGE
    freopen("in.txt", "r", stdin);
    #endif
    using namespace KD_Tree;

    read(point_cnt);
    rep (i, 1, point_cnt)
        read(stk[i].x), read(stk[i].y);

    root = build(1, point_cnt, 0);

    int Q, opt, x, y;
    read(Q);

    while (Q--)
    {
        read(opt), read(x), read(y);
        switch (opt)
        {
            case 0 : 
                insert(root, x, y, 0);
                if (rebuild_need)
                    rebuild();
                break ;
            case 1 : 
                printf("%d\n", Query(x, y, 0));
                break ;
            case 2 : 
                printf("%d\n", Query(x, y, 1));
                break ;
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值