【BZOJ1941】Hide and Seek(SDOI2010)-KD树

测试地址:Hide and Seek
做法:本题需要用到KD树。
KD树是一种维护空间中点集的数据结构,构造方法网上应该有挺多讲解,这里就不赘述了,而这道题中求曼哈顿距离最大和最小是KD树的经典应用,一次查询的复杂度最好是O(logn),最坏是O(n),这样就可以通过此题了。
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
const int inf=1000000000;
int n,rt,ansmax,ansmin,qryx,qryy,D;
struct point
{
    int d[2];
}p[100010];
struct node
{
    int d[2],ch[2],x[2],y[2];
}a[100010];

bool operator < (point a,point b)
{
    return a.d[D]==b.d[D]?a.d[D^1]<b.d[D^1]:a.d[D]<b.d[D];
}

void pushup(int no)
{
    int lc=a[no].ch[0],rc=a[no].ch[1];
    if (lc)
    {
        a[no].x[0]=min(a[no].x[0],a[lc].x[0]);
        a[no].x[1]=max(a[no].x[1],a[lc].x[1]);
        a[no].y[0]=min(a[no].y[0],a[lc].y[0]);
        a[no].y[1]=max(a[no].y[1],a[lc].y[1]);
    }
    if (rc)
    {
        a[no].x[0]=min(a[no].x[0],a[rc].x[0]);
        a[no].x[1]=max(a[no].x[1],a[rc].x[1]);
        a[no].y[0]=min(a[no].y[0],a[rc].y[0]);
        a[no].y[1]=max(a[no].y[1],a[rc].y[1]);
    }
}

int buildtree(int l,int r,int f)
{
    if (l>r) return 0;
    int mid=(l+r)>>1;
    D=f;
    nth_element(p+l,p+mid,p+r+1);
    a[mid].d[0]=a[mid].x[0]=a[mid].x[1]=p[mid].d[0];
    a[mid].d[1]=a[mid].y[0]=a[mid].y[1]=p[mid].d[1];
    a[mid].ch[0]=buildtree(l,mid-1,f^1);
    a[mid].ch[1]=buildtree(mid+1,r,f^1);
    pushup(mid);
    return mid;
}

int getmax(int no)
{
    return max(qryx-a[no].x[0],a[no].x[1]-qryx)+max(qryy-a[no].y[0],a[no].y[1]-qryy);
}

int getmin(int no)
{
    return max(a[no].x[0]-qryx,0)+max(qryx-a[no].x[1],0)+max(a[no].y[0]-qryy,0)+max(qryy-a[no].y[1],0);
}

void querymax(int v)
{
    if (a[v].d[0]!=qryx||a[v].d[1]!=qryy)
        ansmax=max(ansmax,abs(qryx-a[v].d[0])+abs(qryy-a[v].d[1]));
    int dis[2]={-inf,-inf};
    if (a[v].ch[0]) dis[0]=max(dis[0],getmax(a[v].ch[0]));
    if (a[v].ch[1]) dis[1]=max(dis[1],getmax(a[v].ch[1]));
    bool t=(dis[0]<=dis[1]);
    if (dis[t]>ansmax) querymax(a[v].ch[t]);
    t^=1;
    if (dis[t]>ansmax) querymax(a[v].ch[t]);
}

void querymin(int v)
{
    if (a[v].d[0]!=qryx||a[v].d[1]!=qryy)
        ansmin=min(ansmin,abs(qryx-a[v].d[0])+abs(qryy-a[v].d[1]));
    int dis[2]={inf,inf};
    if (a[v].ch[0]) dis[0]=min(dis[0],getmin(a[v].ch[0]));
    if (a[v].ch[1]) dis[1]=min(dis[1],getmin(a[v].ch[1]));
    bool t=(dis[0]>=dis[1]);
    if (dis[t]<ansmin) querymin(a[v].ch[t]);
    t^=1;
    if (dis[t]<ansmin) querymin(a[v].ch[t]);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&p[i].d[0],&p[i].d[1]);

    rt=buildtree(1,n,0);
    int ans=inf;
    for(int i=1;i<=n;i++)
    {
        qryx=p[i].d[0],qryy=p[i].d[1];
        ansmax=-inf;
        querymax(rt);
        ansmin=inf;
        querymin(rt);
        ans=min(ans,ansmax-ansmin);
    }
    printf("%d",ans);

    return 0;
}
posted @ 2018-04-29 19:07  Maxwei_wzj  阅读(179)  评论(0编辑  收藏  举报