bzoj-1941 Hide and Seek

题意:

给出平面上n个点,求距离每个点最大距离减最小距离(不算自己)的最小值;

n<=500000;


题解:

今天写了两道KDTree然而另一道被常数卡飞。。所以就写这个不需要重构的题解吧;

虽说如此但是这毕竟还是裸题啊。。

KD树在实现的时候需要注意一些问题。。

就是每次到了下一个深度都要换一个不同的比较函数来进行排序建树;

否则似乎就变成和线段树/平衡树一样的东西了,那样剪枝的效果会大大下降;

c++的库函数中有nth_element这个神物来直接找到中间值,并分别将小于和大于的元素放在两边

有了这个似乎真是省去了不少麻烦呢。。

然后就是KD树的强剪枝方法,对于每个结点维护子树内所有点覆盖到的最大的K维几何体;

剪枝条件就是计算这个几何体离查询点的最大/最小距离,然后规划先搜索那个子树,减掉该剪的枝就可以了;

因为这道题没有插入所有还是很兹瓷的!时间复杂度?不知道哦!


代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 500100
using namespace std;
struct Point
{
	int x[2];
	friend int dis(Point a,Point b)
	{
		return abs(a.x[0]-b.x[0])+abs(a.x[1]-b.x[1]);
	}
}a[N],low[N],upp[N];
int ch[N][2];
int k,ban,af,ac;
bool cmp(Point a,Point b)
{
	if(a.x[k]!=b.x[k])
	return a.x[k]<b.x[k];
	return a.x[!k]<b.x[!k];
}
void Pushup(int rt)
{
	if(ch[rt][0])
	{
		low[rt].x[0]=min(low[rt].x[0],low[ch[rt][0]].x[0]);
		low[rt].x[1]=min(low[rt].x[1],low[ch[rt][0]].x[1]);
		upp[rt].x[0]=max(upp[rt].x[0],upp[ch[rt][0]].x[0]);
		upp[rt].x[1]=max(upp[rt].x[1],upp[ch[rt][0]].x[1]);
	}
	if(ch[rt][1])
	{
		low[rt].x[0]=min(low[rt].x[0],low[ch[rt][1]].x[0]);
		low[rt].x[1]=min(low[rt].x[1],low[ch[rt][1]].x[1]);
		upp[rt].x[0]=max(upp[rt].x[0],upp[ch[rt][1]].x[0]);
		upp[rt].x[1]=max(upp[rt].x[1],upp[ch[rt][1]].x[1]);
	}
}
int Build(int l,int r,int deep)
{
	if(l>r)	return 0;
	int mid=l+r>>1;
	k=deep&1;
	nth_element(a+l,a+mid,a+r+1,cmp);
	ch[mid][0]=Build(l,mid-1,deep+1);
	ch[mid][1]=Build(mid+1,r,deep+1);
	low[mid]=upp[mid]=a[mid];
	Pushup(mid);
	return mid;
}
int calf(int rt)
{
	return max(abs(low[rt].x[0]-a[ban].x[0]),abs(a[ban].x[0]-upp[rt].x[0]))+
		max(abs(low[rt].x[1]-a[ban].x[1]),abs(a[ban].x[1]-upp[rt].x[1]));
}
int calc(int rt)
{
	return max(low[rt].x[0]-a[ban].x[0],0)+max(a[ban].x[0]-upp[rt].x[0],0)+
		max(low[rt].x[1]-a[ban].x[1],0)+max(a[ban].x[1]-upp[rt].x[1],0);
}
void queryf(int rt)
{
	if(!rt)	return ;
	af=max(af,dis(a[ban],a[rt]));
	int l=calf(ch[rt][0]),r=calf(ch[rt][1]);
	if(l>r)
	{
		if(l>af)	queryf(ch[rt][0]);
		if(r>af)	queryf(ch[rt][1]);
	}
	else
	{
		if(r>af)	queryf(ch[rt][1]);
		if(l>af)	queryf(ch[rt][0]);
	}
}
void queryc(int rt)
{
	if(!rt)	return ;
	if(rt!=ban)
		ac=min(ac,dis(a[ban],a[rt]));
	int l=calc(ch[rt][0]),r=calc(ch[rt][1]);
	if(l<r)
	{
		if(l<ac)	queryc(ch[rt][0]);
		if(r<ac)	queryc(ch[rt][1]);
	}
	else
	{
		if(r<ac)	queryc(ch[rt][1]);
		if(l<ac)	queryc(ch[rt][0]);
	}
}
int main()
{
	int n,m,i,j,k,x,y,rt,ans;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d%d",a[i].x,a[i].x+1);
	rt=Build(1,n,0);
	ans=0x3f3f3f3f;
	for(i=1;i<=n;i++)
	{
		ban=i;
		af=0;
		ac=0x3f3f3f3f;
		queryf(rt);
		queryc(rt);
		ans=min(ans,af-ac);
	}
	printf("%d\n",ans);
	return 0;
}



你可能感兴趣的:(bzoj,KDTree)