[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章