[SDOI2010]Hide and Seek

题目

非常显然就是求一下距离每一个点曼哈顿距离最近的点和最远的点就好了

最远点非常好算,我们建完\(kd-tree\)之后直接暴力就好了

找最近点的时候会有这样一个问题,就是自己找到了自己

所以我们需要像线段树那样,做一个单点修改,找到那个点的位置,把那个点的坐标修改成\((inf,inf)\),之后再查询就好了

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
    char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=1e5+5;
const int inf=600000005;
int mx[maxn][2],mi[maxn][2],id[maxn],l[maxn],r[maxn],fa[maxn],pos[maxn],Ans[maxn];
struct Point{int x[2],rk;}p[maxn],a[maxn];
int n,op,cnt,ans;
inline int cmp(Point A,Point B) {return A.x[op]<B.x[op];}
inline void pushup(int k) {
    mx[k][0]=mi[k][0]=p[id[k]].x[0];
    mx[k][1]=mi[k][1]=p[id[k]].x[1];
    for(re int i=0;i<2;i++) {
        if(l[k]) mx[k][i]=max(mx[k][i],mx[l[k]][i]),
                 mi[k][i]=min(mi[k][i],mi[l[k]][i]);
        if(r[k]) mx[k][i]=max(mx[k][i],mx[r[k]][i]),
                 mi[k][i]=min(mi[k][i],mi[r[k]][i]);
    }
}
int build(int x,int y,int o,int f) {
    if(x>y) return 0;
    int mid=x+y>>1,k=++cnt;
    op=o,std::nth_element(p+x,p+mid,p+y+1,cmp);
    id[k]=mid,pos[p[mid].rk]=k;fa[k]=f;
    l[k]=build(x,mid-1,o^1,k),r[k]=build(mid+1,y,o^1,k);
    pushup(k);return k;
}
inline int dis(Point A,Point B) {
    return abs(A.x[0]-B.x[0])+abs(A.x[1]-B.x[1]);
}
inline int getmax(Point A,int k) {
    int res=0;
    for(re int i=0;i<2;i++) {
        int a=abs(A.x[i]-mx[k][i]),b=abs(A.x[i]-mi[k][i]);
        res+=max(a,b);
    }
    return res;
}
void ask(Point A,int k) {
    int d=dis(A,p[id[k]]);
    ans=max(ans,d);
    int dl=-inf,dr=-inf;
    if(l[k]) dl=getmax(A,l[k]);
    if(r[k]) dr=getmax(A,r[k]);
    if(dl>dr) {
        if(dl>ans) ask(A,l[k]);
        if(dr>ans) ask(A,r[k]);
    }
    else {
        if(dr>ans) ask(A,r[k]);
        if(dl>ans) ask(A,l[k]);
    }
}
inline void change(int k,int x) {
    id[k]=x;pushup(k);k=fa[k];
    while(k) {pushup(k);k=fa[k];}
}
inline int getmin(Point A,int k) {
    int res=0;
    for(re int i=0;i<2;i++) {
        if(A.x[i]>=mi[k][i]&&A.x[i]<=mx[k][i]) continue;
        if(A.x[i]<mi[k][i]) res+=mi[k][i]-A.x[i];
            else if(A.x[i]>mx[k][i]) res+=A.x[i]-mx[k][i];
    }
    return res;
}
void query(Point A,int k) {
    int d=dis(A,p[id[k]]);
    ans=min(ans,d);
    int dl=inf,dr=inf;
    if(l[k]) dl=getmin(A,l[k]);
    if(r[k]) dr=getmin(A,r[k]);
    if(dl<dr) {
        if(dl<ans) query(A,l[k]);
        if(dr<ans) query(A,r[k]);
    }
    else {
        if(dr<ans) query(A,r[k]);
        if(dl<ans) query(A,l[k]);
    }
}
int main() {
    n=read();
    for(re int i=1;i<=n;i++) p[i].x[0]=read(),p[i].x[1]=read(),p[i].rk=i;
    for(re int i=1;i<=n;i++) a[i]=p[i];
    build(1,n,0,0);p[n+1].x[0]=p[n+1].x[1]=inf;
    for(re int i=1;i<=n;i++) 
        ans=0,ask(a[i],1),Ans[i]=ans;
    for(re int i=1;i<=n;i++) {
        int pre=id[pos[i]];
        change(pos[i],n+1);
        ans=inf,query(a[i],1),Ans[i]-=ans;
        change(pos[i],pre);
    }
    ans=inf;
    for(re int i=1;i<=n;i++) ans=min(ans,Ans[i]);
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/10754984.html