BZOJ 2648 SJY摆棋子(KD树)

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2716

【题目大意】

  给出一些点,同时不断插入点和询问某点离插入点最近距离

【题解】

  我们对于给定的点直接建树,之后动态插入查询即可,重建会超时,
  直接插入就可以过了

【代码】

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1500000,INF=1e9;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
namespace KD_Tree{
    struct Dot{
        int d[2],mn[2],mx[2],l,r,sz;
        Dot(){l=r=0;}
        Dot(int x,int y){d[0]=x;d[1]=y;l=r=sz=0;}
        int& operator [] (int x){return d[x];}
    };
    int D,pt[N],dcnt=0;
    Dot T[N],p[N];
    bool operator<(Dot a,Dot b){return a[D]<b[D];}
    inline void umax(int&a,int b){if(a<b)a=b;}
    inline void umin(int&a,int b){if(a>b)a=b;}
    inline bool cmp(int x,int y){return T[x][D]<T[y][D];}
    inline void up(int x){
        T[x].sz=T[T[x].l].sz+T[T[x].r].sz+1;
        T[x].mn[0]=T[x].mx[0]=T[x][0];
        T[x].mn[1]=T[x].mx[1]=T[x][1];
        if(T[x].l){
            umax(T[x].mx[0],T[T[x].l].mx[0]);
            umin(T[x].mn[0],T[T[x].l].mn[0]);
            umax(T[x].mx[1],T[T[x].l].mx[1]);
            umin(T[x].mn[1],T[T[x].l].mn[1]);
        }
        if(T[x].r){
            umax(T[x].mx[0],T[T[x].r].mx[0]);
            umin(T[x].mn[0],T[T[x].r].mn[0]);
            umax(T[x].mx[1],T[T[x].r].mx[1]);
            umin(T[x].mn[1],T[T[x].r].mn[1]);
        }
    }
    inline int NewDot(int x,int y){
        ++dcnt; pt[dcnt]=dcnt;
        T[dcnt][0]=x; T[dcnt][1]=y;
        return up(dcnt),dcnt;
    }
    void AddDot(int x,int y){
        ++dcnt; pt[dcnt]=dcnt;
        p[dcnt][0]=x; p[dcnt][1]=y;
    }
    // 曼哈顿距离估价函数
    inline int dist(int p1,int px,int py){
        int dis=0;
        if(px<T[p1].mn[0])dis+=T[p1].mn[0]-px;
        if(px>T[p1].mx[0])dis+=px-T[p1].mx[0];
        if(py<T[p1].mn[1])dis+=T[p1].mn[1]-py;
        if(py>T[p1].mx[1])dis+=py-T[p1].mx[1];
        return dis;
    }
    //查询(px,py)最近点距离
    int ans=0;
    inline void ask(int x,int px,int py){
        int dl,dr,d0=abs(T[x][0]-px)+abs(T[x][1]-py);
        if(d0<ans)ans=d0;
        dl=T[x].l?dist(T[x].l,px,py):INF;
        dr=T[x].r?dist(T[x].r,px,py):INF;
        if(dl<dr){
            if(dl<ans)ask(T[x].l,px,py);
            if(dr<ans)ask(T[x].r,px,py);
        }else{
            if(dr<ans)ask(T[x].r,px,py);
            if(dl<ans)ask(T[x].l,px,py);
        }
    }
    int query(int x,int px,int py){
        ans=INF; ask(x,px,py);
        return ans;
    }
    void Insert(int&x,int D,const Dot&p){
        if(!x){x=NewDot(p.d[0],p.d[1]);return;}
        if(p.d[D]<T[x][D])Insert(T[x].l,D^1,p);
        else Insert(T[x].r,D^1,p);
        up(x);
    }
    // 建树
    int build(int l,int r,int now){
        int mid=(l+r)>>1;
        D=now;
        nth_element(p+l,p+mid,p+r+1);
        T[mid]=p[mid];
        for(int i=0;i<2;i++)T[mid].mn[i]=T[mid].mx[i]=T[mid][i];
        if(l<mid)T[mid].l=build(l,mid-1,now^1);
        if(r>mid)T[mid].r=build(mid+1,r,now^1);
        return up(mid),mid;
    }
    // 暴力重构
    int Rebuild(int l,int r,int now){
        if(l>r)return 0;
        int mid=(l+r)>>1,x;
        D=now;
        nth_element(pt+l,pt+mid,pt+r+1,cmp);
        x=pt[mid];
        T[x].l=Rebuild(l,mid-1,now^1);
        T[x].r=Rebuild(mid+1,r,now^1);
        return up(x),x;
    }
}
int n,m,x,y,root=0,c;
int main(){
    n=read(); m=read();
    for(int i=1;i<=n;i++)KD_Tree::AddDot(read(),read());
    root=KD_Tree::build(1,KD_Tree::dcnt,0);
    while(m--){
        if(read()==1)KD_Tree::Insert(root,0,KD_Tree::Dot(read(),read()));
        else printf("%d\n",KD_Tree::query(root,read(),read()));
        // if(KD_Tree::dcnt%5000==0)root=KD_Tree::Rebuild(1,KD_Tree::dcnt,0);
        // 重构会超时,不重构能过
    }return 0;
}
时间: 2024-08-29 05:03:31

BZOJ 2648 SJY摆棋子(KD树)的相关文章

BZOJ 2648: SJY摆棋子(K-D Tree)

Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 6051  Solved: 2113[Submit][Status][Discuss] Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子.此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) .现在给出N<=500000个初始棋子.和M<=5

BZOJ 2648(SJY摆棋子-KD_Tree)

2648: SJY摆棋子 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1180  Solved: 391 [Submit][Status][Discuss] Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子.此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) .现在给出N<=5000

BZOJ 2648 SJY摆棋子 / 2716 Violet 3 天使玩偶 K-D树

题目大意:平面上有一些点,问一个点周围离它最近的点的曼哈顿距离是多少.支持动态加点. 思路:CDQ分治可以离线解决,但是SJY是卡CDQ的,天使玩偶可以过.毕竟K-D树的O(sqrt(n))的时间复杂度摆在那. K-D树理解起来其实不难,有k个维度的时候,每一层按照一个维度排序,取出按照这个维度排序的中位数,当作这个块的根,然后将这个块分开.还有一个比较重要的东西就是估价函数,这个函数根据不同的题可能不同.股价函数的主要用途就是对搜索进行剪枝,如果估价函数就已经大于当前的最优答案了,那就不用搜这

bzoj 2648 SJY摆棋子 cdq分治+树状数组

题面 题目传送门 解法 同bzoj2716 自己cdq写的还是丑啊,别人A掉了我T飞了 代码 #include <bits/stdc++.h> #define inf 1 << 30 #define N 1000010 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x, y);} template <typename node>

BZOJ 2648: SJY摆棋子

Descrption 平面求最近点...\(n\leqslant 5\times 10^5\) Solution KD-Tree. 双倍经验..BZOJ 2716: [Violet 3]天使玩偶 Code /************************************************************** Problem: 2648 User: BeiYu Language: C++ Result: Accepted Time:13864 ms Memory:32560

bzoj 2648: SJY摆棋子&amp;&amp;2716: [Violet 3]天使玩偶 --kdtree

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

bzoj 2648 SJY摆棋子——KDtree

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2648 第一道KDtree! 学习资料:https://blog.csdn.net/zhl30041839/article/details/9277807 https://www.cnblogs.com/galaxies/p/kdtree.html 这道题的代码是学习(抄)的这里的:https://blog.csdn.net/lych_cys/article/details/50809141

BZOJ 2648 SJY摆棋子 K-Dimensional-Tree

题目大意:给定平面上的n个点,定义距离为曼哈顿距离,支持下列操作: 1.插入一个点 2.查询离一个点最近的点的距离 Hint说KDTree[可以]过,那么不写KDT还能写啥= = 我的CDQ分治可是T掉了啊= = 记住KDT发生TLE事件的时候不一定是常数问题 有可能写挂了= =(这不和莫队一样么233 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm>

【BZOJ】2648: SJY摆棋子 &amp; 2716: [Violet 3]天使玩偶(kdtree)

http://www.lydsy.com/JudgeOnline/problem.php?id=2716 http://www.lydsy.com/JudgeOnline/problem.php?id=2648 双倍经验题... kdtree裸题吧.....今天学了下kdtree...感觉挺简单的.... 其实就是对几何图形进行剖分建树,而特殊在于,x和y轴轮流剖....这样可以提供很好的性质以便于查找... (一开始脑补了个treap代替kdtree.....显然我脑残了....写到一半发现这