• 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
    ",KD_Tree::query(root,read(),read()));
            // if(KD_Tree::dcnt%5000==0)root=KD_Tree::Rebuild(1,KD_Tree::dcnt,0); 
            // 重构会超时,不重构能过 
        }return 0;
    }
  • 相关阅读:
    冒泡型事件
    非IE浏览器中table标签出现边框的问题
    (转).NET使用一般处理程序生成验证码
    如何使用FreeTextBox
    如何使用DropDownList进行数据绑定并获取值
    (转).NET中获取字符串的MD5码
    (转).NET在后置代码中输入JS提示语句(背景不会变白)
    五大组件之activity(1)
    五大组件之activity(2)Activity的生命周期
    listview里子项有按钮的情况
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj2648.html
Copyright © 2020-2023  润新知