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 kb
****************************************************************/

#include <bits/stdc++.h>
using namespace std;

const int N = 1000500;
const int M = 2;
//const int oo = 0x3f3f3f3f;
const int oo = 0x7fffffff;

inline int in(int x=0,char s=getchar(),int v=1) { while(s>‘9‘||s<‘0‘) v=s==‘-‘?-1:v,s=getchar();
    while(s>=‘0‘&&s<=‘9‘) x=x*10+s-‘0‘,s=getchar();return x*v; }

namespace KDTree {
    struct Node {
        int mi[M],mx[M],d[M],ch[2];
        Node() {
            ch[0]=ch[1]=0;
            for(int i=0;i<M;i++) mx[i]=-oo,mi[i]=oo,d[i]=0;
        }
    }p[N];
    int D,cp,ans,rt;

    #define lc p[o].ch[0]
    #define rc p[o].ch[1]
    #define mid ((l+r)>>1)

    int cmp(const Node &a,const Node &b) { return a.d[D]<b.d[D]; }
    int dis(const Node &a,const Node &b) {
        int res=0;
        for(int i=0;i<M;i++) res+=abs(a.d[i]-b.d[i]);
        return res;
    }
    int Newnode(Node a) {
        ++cp;p[cp]=Node();
        for(int i=0;i<M;i++) p[cp].d[i]=a.d[i];
        return cp;
    }
    void Update(int o) {
        for(int i=0;i<M;i++) p[o].mi[i]=p[o].mx[i]=p[o].d[i];
        if(lc) for(int i=0;i<M;i++)
            p[o].mi[i]=min(p[o].mi[i],p[lc].mi[i]),p[o].mx[i]=max(p[o].mx[i],p[lc].mx[i]);
        if(rc) for(int i=0;i<M;i++)
            p[o].mi[i]=min(p[o].mi[i],p[rc].mi[i]),p[o].mx[i]=max(p[o].mx[i],p[rc].mx[i]);
    }
    void Build(int &o,int l,int r,int d) {
        D=d,o=mid,nth_element(p+l,p+o,p+r+1,cmp);
        if(l<o) Build(lc,l,mid-1,(d+1)%M);
        if(r>o) Build(rc,mid+1,r,(d+1)%M);
        Update(o);
    }
    void insert(int &o,int d,Node a) {
        if(!o) o=Newnode(p[o]),p[o]=a;
        else if(a.d[d]<p[o].d[d]) insert(lc,(d+1)%M,a);
        else insert(rc,(d+1)%M,a);
//      cout<<o<<" "<<lc<<" "<<rc<<" "<<p[o].d[0]<<" "<<p[o].d[1]<<endl;
        Update(o);
    }
    int S(int o,const Node a) {
        int res=0;
        for(int i=0;i<M;i++) res+=max(0,p[o].mi[i]-a.d[i])+max(0,a.d[i]-p[o].mx[i]);
        return res;
    }
    void Query(int o,Node a) {
        if(!o) return;
        ans=min(ans,dis(a,p[o]));
        int ll=lc?S(lc,a):oo,rr=rc?S(rc,a):oo;
        if(ll<rr) {
            if(ll<ans) Query(lc,a);
            if(rr<ans) Query(rc,a);
        } else {
            if(rr<ans) Query(rc,a);
            if(ll<ans) Query(lc,a);
        }
    }
    int Qur(Node a) { return ans=oo,Query(rt,a),ans; }
};

using namespace KDTree;

int n,q;

int main() {
    cp=n=in(),q=in();
    for(int i=1;i<=n;i++) for(int j=0;j<M;j++) p[i].d[j]=in();
    Build(rt=1,1,n,0);
    for(int i=1;i<=q;i++) {
        int opt=in();Node a=Node();
        for(int i=0;i<M;i++) a.d[i]=in();
        if(opt==1) insert(rt,0,a);
        else printf("%d\n",Qur(a));
    }return 0;
}

  

时间: 2024-10-23 14:03:15

BZOJ 2648: SJY摆棋子的相关文章

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摆棋子&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摆棋子(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摆棋子——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摆棋子(KD树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2716 [题目大意] 给出一些点,同时不断插入点和询问某点离插入点最近距离 [题解] 我们对于给定的点直接建树,之后动态插入查询即可,重建会超时, 直接插入就可以过了 [代码] #include <cstdio> #include <algorithm> using namespace std; const int N=1500000,INF=1e9; inline in

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摆棋子 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摆棋子 &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.....显然我脑残了....写到一半发现这