zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    hdu 4614 线段树 二分
    cf 1066d 思维 二分
    lca 最大生成树 逆向思维 2018 徐州赛区网络预赛j
    rmq学习
    hdu 5692 dfs序 线段树
    dfs序介绍
    poj 3321 dfs序 树状数组 前向星
    cf 1060d 思维贪心
    【PAT甲级】1126 Eulerian Path (25分)
    【PAT甲级】1125 Chain the Ropes (25分)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793424.html
Copyright © 2011-2022 走看看