题解[SDOI2010]捉迷藏

Posted h-lka

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解[SDOI2010]捉迷藏相关的知识,希望对你有一定的参考价值。

题目链接:https://www.luogu.com.cn/problem/P2479

题目大意:求平面(n)个点中,到其它(n-1)个点的曼哈顿距离最大和最小距离之差最小的点,求出这个这个距离差。

(K-D-Tree)维护区间,剪枝搜索。

值得一提的是,对于(maxdis)的查询还是比较显然的,找到它到当前点所维护区间的端点的距离的最大值即可。对于最小距离……还是(对我来说)有点坑的。

首先,判断最小距离的时候,当这个点在当前询问区间的话,它的距离显示为0,就炸了qwq,所以,求完这个距离,我们更新答案的时候应该判断是否是真的这个距离,即为零不更新。

那么其它的都和(k)远点对差不多,没有重构,没有替罪羊

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int MAXN=5e5+10;
#define inf 2147483647
struct pt{
    int x[2];
}p[MAXN];
int rt,D,tot,n,ans,ans1,ans2;
int ls[MAXN],rs[MAXN];
struct node{
    int mi[2],mx[2],siz;
    pt c;
}tr[MAXN];
inline void pushup(int x){
    int l=ls[x],r=rs[x];
    tr[x].siz=tr[l].siz+tr[r].siz+1;
    for(int i=0;i<=1;++i){
        tr[x].mi[i]=tr[x].mx[i]=tr[x].c.x[i];
        if(l)tr[x].mi[i]=min(tr[x].mi[i],tr[l].mi[i]),tr[x].mx[i]=max(tr[x].mx[i],tr[l].mx[i]);
        if(r)tr[x].mi[i]=min(tr[x].mi[i],tr[r].mi[i]),tr[x].mx[i]=max(tr[x].mx[i],tr[r].mx[i]);
    }
}
int operator<(pt a,pt b){return a.x[D]<b.x[D];}
int build(int l,int r,int d){
    if(l>r)return 0;
    int x=++tot,mid=l+r>>1;
    D=d;nth_element(p+l,p+mid,p+r+1);
    tr[x].c=p[mid];ls[x]=build(l,mid-1,d^1);
    rs[x]=build(mid+1,r,d^1);pushup(x);return x;
}
inline int abs(int x){return x<0?-x:x;}
inline int Get(pt x,pt y){return abs(x.x[0]-y.x[0])+abs(x.x[1]-y.x[1]);}
int Getdis(int x,pt a){
    int res=0;
    for(int i=0;i<=1;++i){
        res+=max(0,a.x[i]-tr[x].mx[i])+max(0,tr[x].mi[i]-a.x[i]);
    }
    return res;//min
}
int getdis(int x,pt a){
    int res=0;
    for(int i=0;i<=1;++i)res+=max(abs(tr[x].mi[i]-a.x[i]),abs(tr[x].mx[i]-a.x[i]));
    return res;//max
}
void querymax(int x,pt y){
    ans2=max(ans2,Get(tr[x].c,y));
    int l=ls[x],r=rs[x],dl,dr;
    dl=l?getdis(l,y):-inf;
    dr=r?getdis(r,y):-inf;
    if(dl>dr){
        if(dl>ans2)querymax(l,y);
        if(dr>ans2)querymax(r,y);
    }
    else{
        if(dr>ans2)querymax(r,y);
        if(dl>ans2)querymax(l,y);
    }
}
void querymin(int x,pt y){
    int tmp=Get(tr[x].c,y);
    if(tmp)ans1=min(ans1,tmp);
    int l=ls[x],r=rs[x],dl,dr;
    dl=l?Getdis(l,y):inf;
    dr=r?Getdis(r,y):inf;
    if(dl<dr){
        if(dl<ans1)querymin(l,y);
        if(dr<ans1)querymin(r,y);
    }
    else{
        if(dr<ans1)querymin(r,y);
        if(dl<ans1)querymin(l,y);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d%d",&p[i].x[0],&p[i].x[1]);
    rt=build(1,n,0);ans=inf;
    for(int i=1;i<=n;++i){
        ans1=inf,ans2=-inf;
        querymax(rt,p[i]);
        querymin(rt,p[i]);
        ans=min(ans,ans2-ans1);
        //cout<<"Casepoint"<<i<<":"<<ans<<" "<<ans2<<" "<<ans1<<endl;
    }
    printf("%d
",ans);
    return 0;
}

以上是关于题解[SDOI2010]捉迷藏的主要内容,如果未能解决你的问题,请参考以下文章

[SDOI2010]捉迷藏

SDOI2010 捉迷藏 —— KD-Tree

luoguP2479 [SDOI2010]捉迷藏

[BZOJ1941][Sdoi2010]Hide and Seek

bzoj1941 [Sdoi2010]Hide and Seek

bzoj1941[Sdoi2010]Hide and Seek KD-tree