BZOJ 2648 SJY摆棋子 KDtree

Description

这天,SJY显得无聊。在家自己玩。在一个棋盘上,有N个黑色棋子。他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子。此处的距离是曼哈顿距离 即(|x1-x2|+|y1-y2|)。现在给出N<=500000个初始棋子。和M<=500000个操作。对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离。同一个格子可能有多个棋子。
 
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可以过

解法:KDtree。可以看这篇博客学习KDtree.http://blog.csdn.net/jiangshibiao/article/details/34144829

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int n, m, root, D, op, x, y, ans;
struct node{
    int d[2],l,r,mx[2],mi[2];
}a[800010];
inline int cmp(node a, node b){
    return a.d[D]<b.d[D]||a.d[D]==b.d[D]&&a.d[D^1]<b.d[D^1];
}
inline void up(int k, int s){
    a[k].mi[0] = min(a[k].mi[0], a[s].mi[0]);
    a[k].mi[1] = min(a[k].mi[1], a[s].mi[1]);
    a[k].mx[0] = max(a[k].mx[0], a[s].mx[0]);
    a[k].mx[1] = max(a[k].mx[1], a[s].mx[1]);
}
int build(int l,int r,int dd){
    D=dd; int mid=(l+r)/2;
    nth_element(a+l+1,a+mid+1,a+r+1,cmp);
    a[mid].mi[0]=a[mid].mx[0]=a[mid].d[0];
    a[mid].mi[1]=a[mid].mx[1]=a[mid].d[1];
    if(l!=mid) a[mid].l=build(l,mid-1,dd^1);
    if(mid!=r) a[mid].r=build(mid+1,r,dd^1);
    if(a[mid].l) up(mid,a[mid].l);
    if(a[mid].r) up(mid,a[mid].r);
    return mid;
}
void insert(int k){
    int p=root;D=0;
    while(1){
        up(p, k);
        if(a[k].d[D]<=a[p].d[D]){
            if(!a[p].l){
                a[p].l=k;
                return;
            }
            p=a[p].l;
        }else{
            if(!a[p].r){
                a[p].r=k;
                return;
            }
            p=a[p].r;
        }
        D^=1;
    }
}
//
int getdis(int k){
    int dis = 0;
    if(x<a[k].mi[0]) dis += a[k].mi[0]-x;
    if(x>a[k].mx[0]) dis += x-a[k].mx[0];
    if(y<a[k].mi[1]) dis += a[k].mi[1]-y;
    if(y>a[k].mx[1]) dis += y-a[k].mx[1];
    return dis;
}
void ask(int k){
    int d0=abs(a[k].d[0]-x)+abs(a[k].d[1]-y);
    if(d0<ans) ans=d0;
    int dl = a[k].l?getdis(a[k].l):inf;
    int dr = a[k].r?getdis(a[k].r):inf;
    if(dl<dr){if(dl<ans)ask(a[k].l);if(dr<ans)ask(a[k].r);}
    else{if(dr<ans)ask(a[k].r);if(dl<ans)ask(a[k].l);}
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i].d[0],&a[i].d[1]);
    root=build(1,n,0);
    for(int i=1; i<=m; i++){
        scanf("%d%d%d",&op,&x,&y);
        if(op==1){
            ++n;
            a[n].d[0]=a[n].mi[0]=a[n].mx[0]=x;
            a[n].d[1]=a[n].mi[1]=a[n].mx[1]=y;
            insert(n);
        }else{
            ans=inf;
            ask(root);
            printf("%d\n", ans);
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值