[K-D Tree] 天使玩偶/SJY摆棋子

洛谷 P4169这题第11个点卡不过去,BZOJ 2648这题过了= =

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;

#define RG register int
#define LL long long

template<typename elemType>
inline void Read(elemType &T){
    elemType X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    T=(w?-X:X);
}

namespace KDT{
    const int maxn=1000010;
    const int maxk=2;//K维空间
    const int INF=2147483647;
    int D;

    struct Point{
        int d[2];
        bool operator<(const Point &a)const{return d[D]<a.d[D];}
    };

    struct KD_Tree{   
        int root,index;
        Point point[maxn];
       
        struct KDTree_Node{
            int d[maxk],son[2],x[2],y[2];
        };
        KDTree_Node node[maxn];
       
        void push_up(int u,int v){// u-fa v-son
            node[u].x[0]=min(node[u].x[0],node[v].x[0]);
            node[u].x[1]=max(node[u].x[1],node[v].x[1]);
            node[u].y[0]=min(node[u].y[0],node[v].y[0]);
            node[u].y[1]=max(node[u].y[1],node[v].y[1]);
        }

        int get_Dist(int u,int _x,int _y){//查询(_x,_y)到当前区域u的最小曼哈顿距离
            return max(node[u].x[0]-_x,0)+max(_x-node[u].x[1],0)+max(node[u].y[0]-_y,0)+max(_y-node[u].y[1],0);
        }

        int build_KD_Tree(int L,int R,int d){
            D=d;int u=(L+R)>>1;
            std::nth_element(point+L+1,point+u,point+R+1);
            node[u].d[0]=node[u].x[0]=node[u].x[1]=point[u].d[0];
            node[u].d[1]=node[u].y[0]=node[u].y[1]=point[u].d[1];
            if(L<u){node[u].son[0]=build_KD_Tree(L,u-1,d^1);push_up(u,node[u].son[0]);}
            if(u<R){node[u].son[1]=build_KD_Tree(u+1,R,d^1);push_up(u,node[u].son[1]);}
            return u;
        }

        void build(int n){index=n;D=0;root=build_KD_Tree(1,n,0);}

        void insert_Point(int _x,int _y){
            ++index;D=0;
            point[index].d[0]=_x;
            point[index].d[1]=_y;
            node[index].d[0]=node[index].x[0]=node[index].x[1]=_x;
            node[index].d[1]=node[index].y[0]=node[index].y[1]=_y;
            for(RG p=root;p;D^=1){
                push_up(p,index);
                int &nxt=node[p].son[node[index].d[D]>=node[p].d[D]];
                if(!nxt){nxt=index;return;}
                else p=nxt;
            }
        }

        void query(int u,int _x,int _y,int &res){//查询到(_x,_y)曼哈顿距离最近的点的距离
            int temp=abs(node[u].d[0]-_x)+abs(node[u].d[1]-_y);
            int d[2]; 
            if(node[u].son[0]) d[0]=get_Dist(node[u].son[0],_x,_y);
            else d[0]=INF;
            if(node[u].son[1]) d[1]=get_Dist(node[u].son[1],_x,_y);
            else d[1]=INF;
            res=min(res,temp);
            int v=d[0]>=d[1];
            if(d[v]<res) query(node[u].son[v],_x,_y,res);v^=1;
            if(d[v]<res) query(node[u].son[v],_x,_y,res);
            return;
        }
    };
};

int N,M;
KDT::KD_Tree Tree;

int main(){
    Read(N);Read(M);
    Tree.index=N;
    for(RG i=1;i<=N;++i){
        Read(Tree.point[i].d[0]);
        Read(Tree.point[i].d[1]);
    }
    Tree.build(N);
    while(M--){
        int opt,x,y;
        Read(opt);Read(x);Read(y);
        if(opt==1) Tree.insert_Point(x,y);
        else{
            int Ans=KDT::INF;
            Tree.query(Tree.root,x,y,Ans);
            printf("%d
",Ans);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/AEMShana/p/12979196.html