【题解】[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\n",ans);
	return 0;
}
posted @ 2019-12-07 22:25  Refined_heart  阅读(426)  评论(0编辑  收藏  举报