「K-D Tree 膜板」「BZOJ2648」SJY摆棋子

Description

这天,SJY显得无聊。在家自己玩。在一个棋盘上,有 N 个黑色棋子。他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子。此处的距离是 曼哈顿距离 即 |x1x2|+|y1y2| 。现在给出 N500000 个初始棋子。和 M500000 个操作。对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离。同一个格子可能有多个棋子。

Input

第一行两个数 N,M
以后 M 行,每行3个数 t x y
如果 t=1 那么放下一个黑色棋子
如果 t=2 那么放下一个白色棋子

Output

对于每个 t=2 输出一个最小距离

Sample Input

2 3
1 1
2 3
2 1 2
1 3 3
2 4 2

Sample Output

1
2

HINT

kdtree 可以过

题解

K-D Tree 膜板题
这里用的是替罪羊式加点,效率更高。

My Code

/**************************************************************
    Problem: 2648
    User: infinityedge
    Language: C++
    Result: Accepted
    Time:17728 ms
    Memory:48180 kb
****************************************************************/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>

#define inf 0x3f3f3f3f
#define eps 1e-10

using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;

int Abs(int x){
    return x > 0 ? x : -x;
}
struct point{
    int x, y;
    point(){}
    point(int _x, int _y){
        x = _x; y = _y;
    }
}a[500005];

int cmpx(point a, point b){
    return a.x < b.x;
}
int cmpy(point a, point b){
    return a.y < b.y;
}

struct node{
    int x, y, siz, dt;
    int dx, dy, ux, uy;
    int lc, rc, fa;
};

struct KDTree{
    node d[1000005];
    int sz, rt, lst, tot;
    queue<int> q;
    int newnode(){
        if(!q.empty()){
            int ret = q.front();
            q.pop();
            return lst = ret;
        }
        return lst = ++sz;
    }
    void pushup(int k){
        d[k].dx = d[k].ux = d[k].x;
        d[k].dy = d[k].uy = d[k].y;
        d[k].siz = 1;
        if(d[k].lc){
            d[k].dx = min(d[k].dx, d[d[k].lc].dx);
            d[k].dy = min(d[k].dy, d[d[k].lc].dy);
            d[k].ux = max(d[k].ux, d[d[k].lc].ux);
            d[k].uy = max(d[k].uy, d[d[k].lc].uy);
            d[k].siz += d[d[k].lc].siz;
        }
        if(d[k].rc){
            d[k].dx = min(d[k].dx, d[d[k].rc].dx);
            d[k].dy = min(d[k].dy, d[d[k].rc].dy);
            d[k].ux = max(d[k].ux, d[d[k].rc].ux);
            d[k].uy = max(d[k].uy, d[d[k].rc].uy);
            d[k].siz += d[d[k].lc].siz;
        }
    }
    void build(int &k, int l, int r, int flag, int fa){
        if(l > r) return;
        k = newnode(); d[k].fa = fa; d[k].dt = flag;
    //  printf("%d %d %d\n", k, l, r);
        if(l == r){
            d[k].x = d[k].dx = d[k].ux = a[l].x; d[k].y = d[k].dy = d[k].uy = a[l].y;
            return;
        }
        int mid = (l + r) >> 1;
        if(flag) nth_element(a + l, a + mid, a + r, cmpx);
        else nth_element(a + l, a + mid, a + r, cmpy);
        d[k].x = a[mid].x; d[k].y = a[mid].y;
        build(d[k].lc, l, mid - 1, flag ^ 1, k);
        build(d[k].rc, mid + 1, r, flag ^ 1, k);
        pushup(k);
    }

    int judge(int k){
        if((d[d[k].lc].siz + 1) * 0.8 > d[k].siz + 1) return 1;
        if((d[d[k].lc].siz + 1) * 0.8 > d[k].siz + 1) return 1;
        return 0;
    }
    void dfs(int k){
        q.push(k);
        a[++tot] = point(d[k].x, d[k].y);
        if(d[k].lc) dfs(d[k].lc);
        if(d[k].rc) dfs(d[k].rc);
    }
    void rebuild(int k){
        tot = 0;
        if(k == rt){
            dfs(k);
            build(rt, 1, tot, 0, 0);
            return;
        }
        int f = d[k].fa, wh = (d[f].rc == k);
        dfs(k);
        if(wh) build(d[f].rc, 1, tot, 0, d[f].dt ^ 1);
        else build(d[f].lc, 1, tot, 0, d[f].dt ^ 1);
    }
    void ins(int k, int x, int y, int flag){
        if(flag){
            if(x <= d[k].x){
                if(d[k].lc == 0){
                    a[1] = point(x, y);
                    build(d[k].lc, 1, 1, flag ^ 1, k);
                }else ins(d[k].lc, x, y, flag ^ 1);
            }else{
                if(d[k].rc == 0){
                    a[1] = point(x, y);
                    build(d[k].rc, 1, 1, flag ^ 1, k);
                }else ins(d[k].rc, x, y, flag ^ 1);
            }
        }else{
            if(y <= d[k].y){
                if(d[k].lc == 0){
                    a[1] = point(x, y);
                    build(d[k].lc, 1, 1, flag ^ 1, k);
                }else ins(d[k].lc, x, y, flag ^ 1);
            }else{
                if(d[k].rc == 0){
                    a[1] = point(x, y);
                    build(d[k].rc, 1, 1, flag ^ 1, k);
                }else ins(d[k].rc, x, y, flag ^ 1);
            }
        }
        pushup(k);
    }
    void ins(int x, int y){
        ins(rt, x, y, 0);
        x = lst; int tmp = 0;
        while(x != 0){
            if(judge(x)) tmp = x;
            x = d[x].fa;
        }
        if(tmp != 0){
            rebuild(x);
        }
    }
    int ans;
    int get(int k, int x, int y){
        int ret = 0;
        ret += max(0, d[k].dx - x);
        ret += max(0, d[k].dy - y);
        ret += max(0, x - d[k].ux);
        ret += max(0, y - d[k].uy);
        return ret;
    }
    void query(int k, int x, int y){
    //  printf("%d %d %d\n", rt, d[k].x, d[k].y);
        ans = min(ans, Abs(d[k].x - x) + Abs(d[k].y - y));
        int dl = inf, dr = inf;
        if(d[k].lc) dl = get(d[k].lc, x, y);
        if(d[k].rc) dr = get(d[k].rc, x, y);
        if(dl < dr){
            if(dl < ans) query(d[k].lc, x, y);
            if(dr < ans) query(d[k].rc, x, y);
        }else{
            if(dr < ans) query(d[k].rc, x, y);
            if(dl < ans) query(d[k].lc, x, y);
        }
    }
    int query(int x, int y){
        ans = inf;
        query(rt, x, y);
        return ans;
    }
}KDT;

int n, m;
int main(){
    //freopen("test.in", "r", stdin);
    //freopen("test.out", "w", stdout);
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++){
        int x, y;
        scanf("%d%d", &x, &y);
        a[i] = point(x, y);
    }
    KDT.build(KDT.rt, 1, n, 0, 0);
    for(int i = 1; i <= m; i ++){
        int opt, x, y;
        scanf("%d%d%d", &opt, &x, &y);
        if(opt == 1){
            KDT.ins(x, y);
        }else{
            printf("%d\n", KDT.query(x, y));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/infinity_edge/article/details/79078619