bzoj 2648: SJY摆棋子 KDtree + 替罪羊式重构

KDtree真的很妙啊,真的是又好写,作用还多,以后还需更多学习呀.

对于这道题,我们求的是曼哈顿距离的最小值.

而维护的变量和以往是相同的,就是横纵坐标的最小值与最大值.

我们设为一个极为巧妙且玄学的股价函数.

int getdis(int o,int x1,int y1){
    int dis = 0;
    if(x1 < node[o].minv[0]) dis += node[o].minv[0] - x1;
    if(x1 > node[o].maxv[0]) dis += x1 - node[o].maxv[0]; 
    if(y1 < node[o].minv[1]) dis += node[o].minv[1] - y1; 
    if(y1 > node[o].maxv[1]) dis += y1 - node[o].maxv[1]; 
    return dis; 
 }
void query(int o,int x1,int y1){
    int dn = abs(node[o].p[0] - x1) + abs(node[o].p[1] - y1),dl,dr; 
    ans = min(ans,dn); 
    dl = node[o].ch[0] ? getdis(node[o].ch[0],x1,y1) : inf; 
    dr = node[o].ch[1] ? getdis(node[o].ch[1],x1,y1) : inf; 
    if(dl < dr) {
        if(dl < ans) query(node[o].ch[0],x1,y1); 
        if(dr < ans) query(node[o].ch[1],x1,y1);             
    }
    else {
        if(dr < ans) query(node[o].ch[1],x1,y1); 
        if(dl < ans) query(node[o].ch[0],x1,y1); 
    }
}  

 

设当前矩阵的边界为 (x1,y1),(x2,y2).

那么对于当前要查询的点 $p$ 如果在矩阵外,那么即使是最近距离也是 $p$ 到最近两个矩阵边界的曼哈顿距离和(getdis函数).

我们将上述最理想化距离设为 $w$,即点 $p$ 到矩阵边界的最小距离.

那么,如果点 $p$ 比当前最优解大的话,那么这一棵子树就没有必要查了.

 

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib> 
#define setIO(s) freopen(s".in","r",stdin) 
#define maxn 3000000 
#define inf 100000000 
using namespace std;   
namespace KDtree{     
    int tot;
    int d; 
    int ans; 
    int n;
    int m;                             
    void init(){ tot = n, ans = inf;  }
    int newnode(){ return ++tot; }
    struct Data{
        int ch[2],minv[2],maxv[2],w,sum,p[2];      
    }node[maxn];
    bool cmp(Data i,Data j){
        return i.p[d] == j.p[d] ? i.p[d^1] < j.p[d^1]: i.p[d] < j.p[d]; 
    }
    int isin(int o,int x1,int y1,int x2,int y2){
        if(node[o].minv[0]>=x1&&node[o].maxv[0]<=x2&&node[o].minv[1]>=y1&&node[o].maxv[1]<=y2) return 1;
        return 0;  
    }
    int isout(int o,int x1,int y1,int x2,int y2){
        if(node[o].minv[0] > x2 || node[o].maxv[0] < x1) return 1; 
        if(node[o].minv[1] > y2 || node[o].maxv[1] < y1) return 1;
        return 0; 
    }
    void getmax(int &a,int b){ if( b > a ) a = b; }
    void getmin(int &a,int b){ if( b < a ) a = b; }
    void pushup(int o,int x){
        getmin(node[o].minv[0],node[x].minv[0]); 
        getmin(node[o].minv[1],node[x].minv[1]); 
        getmax(node[o].maxv[1],node[x].maxv[1]); 
        getmax(node[o].maxv[0],node[x].maxv[0]); 
        node[o].sum += node[x].sum; 
    }
    int build(int l,int r,int o){
        int mid = (l + r) >> 1;              
        d = o ; nth_element(node+l,node+mid,node+r+1,cmp); 
        node[mid].minv[0] = node[mid].maxv[0] = node[mid].p[0]; 
        node[mid].minv[1] = node[mid].maxv[1] = node[mid].p[1]; 
        node[mid].sum = node[mid].w; 
        node[mid].ch[0] = node[mid].ch[1] = 0; 
        if(l < mid) node[mid].ch[0] = build(l,mid - 1,o ^ 1), pushup(mid,node[mid].ch[0]); 
        if(r > mid) node[mid].ch[1] = build(mid + 1, r, o ^ 1), pushup(mid,node[mid].ch[1]); 
        return mid; 
    }
    void update(int &o,Data x,int de){
        if(!o) {
            o = newnode();  
            node[o].p[0] = node[o].maxv[0] = node[o].minv[0] = x.p[0]; 
            node[o].p[1] = node[o].minv[1] = node[o].maxv[1] = x.p[1]; 
            return; 
        }
        if(x.p[de] < node[o].p[de]) update(node[o].ch[0],x,de^1),pushup(o,node[o].ch[0]); 
        else update(node[o].ch[1],x,de^1),pushup(o,node[o].ch[1]); 
    }
    int getdis(int o,int x1,int y1){
        int dis = 0;
        if(x1 < node[o].minv[0]) dis += node[o].minv[0] - x1;
        if(x1 > node[o].maxv[0]) dis += x1 - node[o].maxv[0]; 
        if(y1 < node[o].minv[1]) dis += node[o].minv[1] - y1; 
        if(y1 > node[o].maxv[1]) dis += y1 - node[o].maxv[1]; 
        return dis; 
    }
    void query(int o,int x1,int y1){
        int dn = abs(node[o].p[0] - x1) + abs(node[o].p[1] - y1),dl,dr; 
        ans = min(ans,dn); 
        dl = node[o].ch[0] ? getdis(node[o].ch[0],x1,y1) : inf; 
        dr = node[o].ch[1] ? getdis(node[o].ch[1],x1,y1) : inf; 
        if(dl < dr) {
            if(dl < ans) query(node[o].ch[0],x1,y1); 
            if(dr < ans) query(node[o].ch[1],x1,y1);             
        }
        else {
            if(dr < ans) query(node[o].ch[1],x1,y1); 
            if(dl < ans) query(node[o].ch[0],x1,y1); 
        }
    }
    int main(){       
        scanf("%d%d",&n,&m); 
        init(); 
        for(int i = 1;i <= n; ++i) scanf("%d%d",&node[i].p[0],&node[i].p[1]); 
        int root = build(1,n,0); 
        for(int i = 1;i <= m; ++i) {
            int opt,a,b; 
            scanf("%d%d%d",&opt,&a,&b);       
            if(opt == 1) {
                Data k; 
                k.p[0] = a,k.p[1] = b;        
                update(root,k,0);   
                if(i % 300000 == 0) root = build(1,tot,0);   
            }
            if(opt == 2) {
                ans = inf; 
                query(root,a,b); 
                printf("%d\n",ans); 
            }
        }
        return 0; 
    }     
}; 
int main(){
    //setIO("input"); 
    KDtree::main(); 
    return 0; 
}

  

posted @ 2019-04-05 21:40  EM-LGH  阅读(262)  评论(0编辑  收藏  举报