题解 P2479 【[SDOI2010]捉迷藏】

· · 题解

【题意】

求 $\min_{i=1}^{n}(\max_{j=1}^{n}dis(p_i,p_j)-\min_{j=1}^{n}dis(p_i,p_j)(i\ne j))$。 ## 【分析】 平面上的点可以用 K-D Tree 维护。 求与点 $p_i$ 的距离的最大(小)值,可以在 K-D Tree 上搜索。 ### 剪枝1: 对于每个区间,维护覆盖这个点集的矩形的边界。 估价函数设为当前点与该矩形的最近(远)距离,判断当前区间能否产生更优的答案。 ### 剪枝2: 遍历到某个节点时,计算两个子节点的估价函数。 先遍历估价函数更优的子节点。 注意搜索最近距离时不能计算重合的点。 ## 【算法】 K-D Tree ## 【代码】 ```cpp #include<bits/stdc++.h> #define DB double using namespace std; const int maxn=1e5+5,INF=2147483647; const DB A=0.75; int n; int now1,now2; int ans=INF; int D; struct point{ int x[2]; bool operator !=(point b)const{return x[0]!=b.x[0]||x[1]!=b.x[1];} }p[maxn],a[maxn]; bool cmp(point x,point y){ return x.x[D]<y.x[D]; } int max(int x,int y){ return x>y?x:y; } int min(int x,int y){ return x<y?x:y; } int abs(int x){ return x>0?x:-x; } struct KDT{ int tot,rt; int top,rub[maxn]; struct ele{ point p; int l,r,s,mi[2],mx[2]; }t[maxn]; #define mid (l+r>>1) #define ls(k) t[k].l #define rs(k) t[k].r #define p(k) t[k].p #define s(k) t[k].s int New(){ return top?rub[top--]:++tot; } void pushup(int k){ t[k].mi[0]=t[k].mx[0]=p(k).x[0]; t[k].mi[1]=t[k].mx[1]=p(k).x[1]; s(k)=1; if(ls(k)){ t[k].mi[0]=min(t[k].mi[0],t[ls(k)].mi[0]); t[k].mi[1]=min(t[k].mi[1],t[ls(k)].mi[1]); t[k].mx[0]=max(t[k].mx[0],t[ls(k)].mx[0]); t[k].mx[1]=max(t[k].mx[1],t[ls(k)].mx[1]); s(k)+=s(ls(k)); } if(rs(k)){ t[k].mi[0]=min(t[k].mi[0],t[rs(k)].mi[0]); t[k].mi[1]=min(t[k].mi[1],t[rs(k)].mi[1]); t[k].mx[0]=max(t[k].mx[0],t[rs(k)].mx[0]); t[k].mx[1]=max(t[k].mx[1],t[rs(k)].mx[1]); s(k)+=s(rs(k)); } } int build(int l,int r,int d){ if(l>r) return 0; int x=New(); D=d; nth_element(p+l,p+mid,p+r+1,cmp); p(x)=p[mid]; ls(x)=build(l,mid-1,d^1); rs(x)=build(mid+1,r,d^1); pushup(x); return x; } void clear(int k,int pos){ if(ls(k)) clear(ls(k),pos); p[pos+s(ls(k))+1]=p(k); rub[++top]=k; if(rs(k)) clear(rs(k),pos+s(ls(k))+1); } void check(int &k,int d){ int c=A*s(k); if(s(ls(k))>c||s(rs(k))>c){ clear(k,0); k=build(1,s(k),d); } } void insert(int &k,point p,int d){ if(!k){k=New();ls(k)=rs(k)=0,p(k)=p,pushup(k);return;} if(p.x[d]<=p(k).x[d]) insert(ls(k),p,d^1); else insert(rs(k),p,d^1); pushup(k); check(k,d); } int dis1(int x,int y,int x1,int y1,int x2,int y2){ return (x<x1?x1-x:(x>x2?x-x2:0))+(y<y1?y1-y:(y>y2?y-y2:0)); } void query1(int k,point x){ if(!k) return; if(dis1(x.x[0],x.x[1],t[k].mi[0],t[k].mi[1],t[k].mx[0],t[k].mx[1])>now1) return; if(p(k)!=x) now1=min(now1,dis1(x.x[0],x.x[1],p(k).x[0],p(k).x[1],p(k).x[0],p(k).x[1])); int dl=ls(k)?dis1(x.x[0],x.x[1],t[ls(k)].mi[0],t[ls(k)].mi[1],t[ls(k)].mx[0],t[ls(k)].mx[1]):INF, dr=rs(k)?dis1(x.x[0],x.x[1],t[rs(k)].mi[0],t[rs(k)].mi[1],t[rs(k)].mx[0],t[rs(k)].mx[1]):INF; if(dl<=dr){ query1(ls(k),x); query1(rs(k),x); }else{ query1(rs(k),x); query1(ls(k),x); } } int dis2(int x,int y,int x1,int y1,int x2,int y2){ return max(abs(x-x1),abs(x-x2))+max(abs(y-y1),abs(y-y2)); } void query2(int k,point x){ if(!k) return; if(dis2(x.x[0],x.x[1],t[k].mi[0],t[k].mi[1],t[k].mx[0],t[k].mx[1])<now2) return; now2=max(now2,dis2(x.x[0],x.x[1],p(k).x[0],p(k).x[1],p(k).x[0],p(k).x[1])); int dl=ls(k)?dis2(x.x[0],x.x[1],t[ls(k)].mi[0],t[ls(k)].mi[1],t[ls(k)].mx[0],t[ls(k)].mx[1]):-INF, dr=rs(k)?dis2(x.x[0],x.x[1],t[rs(k)].mi[0],t[rs(k)].mi[1],t[rs(k)].mx[0],t[rs(k)].mx[1]):-INF; if(dl>=dr){ query2(ls(k),x); query2(rs(k),x); }else{ query2(rs(k),x); query2(ls(k),x); } } }T; char gc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } #define getchar gc int read(){ int ret=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret*f; } int main(){ freopen("P2479.in","r",stdin); freopen("P2479.out","w",stdout); n=read(); for(int i=1;i<=n;i++){ a[i].x[0]=read(),a[i].x[1]=read(); T.insert(T.rt,a[i],0); } for(int i=1;i<=n;i++){ now1=INF,now2=-INF; T.query1(T.rt,a[i]),T.query2(T.rt,a[i]); ans=min(ans,now2-now1); } printf("%d\n",ans); return 0; } ```