【bzoj2648】SJY摆棋子 KD-tree

题目描述

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

输入

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

输出

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

样例输入

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

样例输出

1
2


题解

KD-tree模板题

然后为了压行把insert写得比较难看

其实KD-tree这个东西和平衡树挺像的,差不多就是维护一个中序遍历,即左子树、根、右子树的某一关键字是递增的。

只不过这个关键字是不断变化的,即每一位轮流作为关键字排序(好像很高端的样子)。

所以这里使用algorithm中的STL函数:nth_element,它取出区间中指定排名的数放到指定位置,然后将小于或大于该数的放到指定位置的两端(注意一下开闭区间啥的)。

然后插入就像平衡树的插入,先找子树,直至找到空节点。

查询时采用一种启发式的思想,使用估价函数getdis,使得随机数据的时间大大减少。

然后这题好像不需要维护树不退化什么的,要维护的话直接重构即可。

#include <cstdio>
#include <algorithm>
#define N 1000010
#define inf 0x7fffffff
using namespace std;
struct data
{
    int p[2] , maxn[2] , minn[2] , c[2];
}a[N];
int root , d , ans;
bool cmp(data a , data b)
{
    return a.p[d] == b.p[d] ? a.p[d ^ 1] < b.p[d ^ 1] : a.p[d] < b.p[d];
}
void pushup(int k , int s)
{
    a[k].maxn[0] = max(a[k].maxn[0] , a[s].maxn[0]);
    a[k].maxn[1] = max(a[k].maxn[1] , a[s].maxn[1]);
    a[k].minn[0] = min(a[k].minn[0] , a[s].minn[0]);
    a[k].minn[1] = min(a[k].minn[1] , a[s].minn[1]);
}
int build(int l , int r , int now)
{
    int mid = (l + r) >> 1;
    d = now , nth_element(a + l , a + mid , a + r + 1 , cmp);
    a[mid].maxn[0] = a[mid].minn[0] = a[mid].p[0];
    a[mid].maxn[1] = a[mid].minn[1] = a[mid].p[1];
    if(l < mid) a[mid].c[0] = build(l , mid - 1 , now ^ 1) , pushup(mid , a[mid].c[0]);
    if(r > mid) a[mid].c[1] = build(mid + 1 , r , now ^ 1) , pushup(mid , a[mid].c[1]);
    return mid;
}
void ins(int k)
{
    int *t = &root;
    d = 0;
    while(*t) pushup(*t , k) , t = &a[*t].c[a[k].p[d] > a[*t].p[d]] , d ^= 1;
    *t = k;
}
int getdis(int k , int x , int y)
{
    int ans = 0;
    if(x < a[k].minn[0]) ans += a[k].minn[0] - x;
    if(x > a[k].maxn[0]) ans += x - a[k].maxn[0];
    if(y < a[k].minn[1]) ans += a[k].minn[1] - y;
    if(y > a[k].maxn[1]) ans += y - a[k].maxn[1];
    return ans;
}
void query(int k , int x , int y)
{
    int dn = abs(x - a[k].p[0]) + abs(y - a[k].p[1]) , dl , dr;
    if(dn < ans) ans = dn;
    dl = a[k].c[0] ? getdis(a[k].c[0] , x , y) : inf;
    dr = a[k].c[1] ? getdis(a[k].c[1] , x , y) : inf;
    if(dl < dr)
    {
        if(dl < ans) query(a[k].c[0] , x , y);
        if(dr < ans) query(a[k].c[1] , x , y);
    }
    else
    {
        if(dr < ans) query(a[k].c[1] , x , y);
        if(dl < ans) query(a[k].c[0] , x , y);
    }
}
int main()
{
    int n , m , i , opt , x , y;
    scanf("%d%d" , &n , &m);
    for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &a[i].p[0] , &a[i].p[1]);
    root = build(1 , n , 0);
    while(m -- )
    {
        scanf("%d%d%d" , &opt , &x , &y);
        if(opt == 1) n ++ , a[n].p[0] = a[n].maxn[0] = a[n].minn[0] = x , a[n].p[1] = a[n].maxn[1] = a[n].minn[1] = y , ins(n);
        else ans = inf , query(root , x , y) , printf("%d\n" , ans);
    }
    return 0;
}

 

 

posted @ 2017-06-02 16:55  GXZlegend  阅读(320)  评论(0编辑  收藏  举报