[Violet]天使玩偶/SJY摆棋子——k-d tree & Scapegoat tree

BZOJ 2648-SJY摆棋子

题目大意

一堆点,可以加点,询问离某个点曼哈顿距离最近的点的曼哈顿距离

Solution

离线做法:cdq分治,代码量蛮短的

这里主要讲在线做法
这是k-d tree的模板题,但是因为有加点操作,所以不能保证k-dtree的重量平衡,可能会使这棵BST的结构变得很难看,随便一卡就能卡掉

所以我们要加上Scapegoat tree来暴力维护它的相对平衡

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#define al 0.75
#define N 1000010
#define INF 0x3f3f3f3f

using namespace std;

int rub[N], WD, top, root, cur, ans;

struct Point {
    int x[2];
    Point(int X = 0, int Y = 0) {
        x[0] = X;
        x[1] = Y;
    }
    inline bool operator < (const Point &o) const {
        return x[WD] < o.x[WD];
    }
}p[N];

struct Node {
    int mi[2], mx[2], ls, rs, sz;
    Point p;
}tr[N];

inline int read() {
    char ch = getchar();
    int x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x;
}

inline int newNode() {
    if (top) return rub[top--];
    return ++cur;
}

inline void pushup(int k) {
    int l = tr[k].ls, r = tr[k].rs;
    for (int i = 0; i < 2; ++i) {
        tr[k].mi[i] = tr[k].mx[i] = tr[k].p.x[i];
        if (l) {
            tr[k].mi[i] = min(tr[k].mi[i], tr[l].mi[i]);
            tr[k].mx[i] = max(tr[k].mx[i], tr[l].mx[i]);
        }
        if (r) {
            tr[k].mi[i] = min(tr[k].mi[i], tr[r].mi[i]);
            tr[k].mx[i] = max(tr[k].mx[i], tr[r].mx[i]);
        }
    }
    tr[k].sz = tr[l].sz + tr[r].sz + 1;
}

inline int build(int l, int r, int wd) {
    if (l > r) return 0;
    int k = newNode(), mid = l + r >> 1;
    WD = wd;
    nth_element(p + l, p + mid, p + r + 1);
    tr[k].p = p[mid];
    tr[k].ls = build(l, mid - 1, wd ^ 1);
    tr[k].rs = build(mid + 1, r, wd ^ 1);
    pushup(k);
    return k;
}

inline void pia(int k, int num) {
    if (tr[k].ls) pia(tr[k].ls, num);
    p[num + tr[tr[k].ls].sz + 1] = tr[k].p;
    rub[++top] = k;
    if (tr[k].rs) pia(tr[k].rs, num + tr[tr[k].ls].sz + 1);
}

inline void check(int &k, int wd) {
    if (al * tr[k].sz < tr[tr[k].ls].sz || al * tr[k].sz < tr[tr[k].rs].sz) {
        pia(k, 0);
        k = build(1, tr[k].sz, wd);
    }
}

inline void ins(Point now, int &k, int wd) {
    if (!k) {
        k = newNode();
        tr[k].p = now;
        tr[k].ls = tr[k].rs = 0;
        pushup(k);
        return;
    }
    if (tr[k].p.x[wd] < now.x[wd]) ins(now, tr[k].rs, wd ^ 1);
    else ins(now, tr[k].ls, wd ^ 1);
    pushup(k);
    check(k, wd);
}

inline int getdis(Point now, int k) {
    int ret = 0;
    for (int i = 0; i < 2; ++i) {
        ret += max(0, now.x[i] - tr[k].mx[i]) + max(0, tr[k].mi[i] - now.x[i]);
    }
    return ret;
}

inline int dis(Point a, Point b) {
    return abs(a.x[0] - b.x[0]) + abs(a.x[1] - b.x[1]);
}

inline void query(Point now, int k) {
    ans = min(ans, dis(now, tr[k].p));
    int dl = INF, dr = INF;
    if (tr[k].ls) dl = getdis(now, tr[k].ls);
    if (tr[k].rs) dr = getdis(now, tr[k].rs);
    if (dl < dr) {
        if (dl < ans) query(now, tr[k].ls);
        if (dr < ans) query(now, tr[k].rs);
    }
    else {
        if (dr < ans) query(now, tr[k].rs);
        if (dl < ans) query(now, tr[k].ls);
    }
}

int main() {
    int n = read(), m = read();
    for (int i = 1; i <= n; ++i) {
        p[i].x[0] = read();
        p[i].x[1] = read();
    }
    root = build(1, n, 0);
    while(m--) {
        int opt = read(), x = read(), y = read();
        if (opt == 1) ins(Point(x, y), root, 0);
        else ans = INF, query(Point(x, y), root), printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值