zoukankan      html  css  js  c++  java
  • 【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
    " , ans);
        }
        return 0;
    }
    

     

  • 相关阅读:
    数据结构与算法JavaScript (一) 栈
    js架构设计模式——前端MVVM框架设计及实现(二)
    js架构设计模式——前端MVVM框架设计及实现(一)
    js架构设计模式——MVC,MVP 和 MVVM 的图示及简单明了的区别说明
    js架构设计模式——你对MVC、MVP、MVVM 三种组合模式分别有什么样的理解?
    js面向对象oop编程
    js模块化开发——前端模块化
    SPRING 集成 activemq 的 topic 模式
    linux yum 本地源配置
    ORACLE 导入的问题
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6934139.html
Copyright © 2011-2022 走看看