BZOJ 2648 SJY擺棋子 K-D Tree

題目大意:給出平面上一些點,要求支持插入點,查詢離某個點的最近點的曼哈頓距離。

KDTree裸題
https://zhuanlan.zhihu.com/p/22557068

#include <cstdio>
#include <algorithm>
#define N 500005
#define INF 2000000000
using namespace std;
const double alpha=0.7;
struct Point {
    int x,y;
    Point() {}
    Point(int _x,int _y):
        x(_x),y(_y) {}
    int operator | (const Point& rhs) const {
        return abs(x-rhs.x)+abs(y-rhs.y);
    }
    void scan() { scanf("%d%d",&x,&y); }
}a[N];
bool cmpx(Point lhs,Point rhs) { return lhs.x<rhs.x; }
bool cmpy(Point lhs,Point rhs) { return lhs.y<rhs.y; }
bool (*cmp[2])(Point,Point)={cmpx,cmpy};
Point min(const Point& lhs,const Point& rhs) {
    return Point(min(lhs.x,rhs.x),min(lhs.y,rhs.y));
}
Point max(const Point& lhs,const Point& rhs) {
    return Point(max(lhs.x,rhs.x),max(lhs.y,rhs.y));
}
int get_mindist(Point o,Point maxx,Point minn) {
    int tmp=0;
    if(cmp[0](o,minn)) tmp+=minn.x-o.x;
    if(cmp[0](maxx,o)) tmp+=o.x-maxx.x;
    if(cmp[1](o,minn)) tmp+=minn.y-o.y;
    if(cmp[1](maxx,o)) tmp+=o.y-maxx.y;
    return tmp;
}
struct Node {
    Node* ch[2];
    Point pos,maxx,minn;
    int siz,mode;
    Node() {}
    Node(Point _pos,bool _mode):mode(_mode) {
        pos=maxx=minn=_pos;
        ch[0]=ch[1]=NULL;
        siz=1;
    }
    void* operator new(size_t) {
        static Node *mempool,*C;
        if(mempool==C) mempool=(C=new Node[1<<20])+(1<<20);
        return C++;
    }
    void maintain() {
        siz=1;
        for(int i=0;i<2;i++)
            if(ch[i]) {
                siz+=ch[i]->siz;
                maxx=max(maxx,ch[i]->maxx);
                minn=min(minn,ch[i]->minn);
            }
        return ;
    }
    bool check() {
        for(int i=0;i<2;i++)
            if(ch[i] && ch[i]->siz>siz*alpha)
                return true;
        return false;
    }
}*root;
void build(Node*& o,int l,int r,int mode) {
    if(l>r) return ;
    int mid=l+r>>1;
    if(l==r) {
        o=new Node(a[mid],mode);
        return ;
    }
    nth_element(a+l,a+mid,a+r+1,cmp[mode]);
    o=new Node(a[mid],mode);
    build(o->ch[0],l,mid-1,mode^1);
    build(o->ch[1],mid+1,r,mode^1);
    o->maintain();
    return ;
}
Node** s[N*2];
int top;
void Insert(Node*& o,Point pos,int mode) {
    if(!o) {
        o=new Node(pos,mode);
        return ;
    }
    int d=cmp[mode](pos,o->pos);
    Insert(o->ch[d^1],pos,mode^1);
    o->maintain();
    if(o->check()) s[++top]=&o;
    return ;
}
int tot;
void Delete(Node*& o) {
    if(o->ch[0]) Delete(o->ch[0]);
    a[++tot]=o->pos;
    if(o->ch[1]) Delete(o->ch[1]);
    return ;
}
void rebuild(Node*& o) {
    top=tot=0;
    bool mode=o->mode;
    Delete(o);
    build(o,1,tot,mode);
    return ;
}
int ans;
void query(Node* o,Point pos) {
    ans=min(ans,pos|o->pos);
    int minn[2];
    for(int i=0;i<2;i++)
        minn[i]=o->ch[i]?get_mindist(pos,o->ch[i]->maxx,o->ch[i]->minn):INF;
    if(minn[0]<minn[1]) {
        if(o->ch[0] && minn[0]<ans) query(o->ch[0],pos);
        if(o->ch[1] && minn[1]<ans) query(o->ch[1],pos);
    }
    else {
        if(o->ch[1] && minn[1]<ans) query(o->ch[1],pos);
        if(o->ch[0] && minn[0]<ans) query(o->ch[0],pos);
    }
    return ;
}
int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) a[i].scan();
    build(root,1,n,0);
    while(m--) {
        int mode;
        Point o;
        scanf("%d",&mode);
        o.scan();
        if(mode==1) {
            top=0;
            Insert(root,o,root->mode);
            if(top) rebuild(*s[top]);
        }
        else {
            ans=INF;
            query(root,o);
            printf("%d\n",ans);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章