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;
    }
  • 相关阅读:
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793424.html
Copyright © 2011-2022 走看看