BJWC 2014 数据 题解

题目传送门

题目大意: 给出 n n n 个点,有 m m m 次操作,每次为:1、添加一个点;2、求点集中离询问点最近的点到询问点的距离;3、询问点集中离询问点最远的点到询问点的距离。

题解

K-D tree裸题。

先维护一下每棵子树对应的矩阵。

找最近点的剪枝是:先去左右子树中离离询问点比较近的矩阵。

找最远点的剪枝:类似的,先去比较远的矩阵。

代码如下:

#include 
#include 
#include 
using namespace std;
#define maxn 500010
#define inf 999999999
#define zuo ch[0]
#define you ch[1]
#define alpha 0.75

int n,m;
const int K=2;
struct point{int d[K];}q[maxn];
int dis(point x,point y){
	int re=0;
	for(int i=0;i<K;i++)re+=abs(x.d[i]-y.d[i]);
	return re;
}
int C;bool cmp(point x,point y){return x.d[C]<y.d[C];}
struct KD_node *root=NULL,*null=NULL;
struct KD_node{
	point x,ld,ru;
	KD_node *ch[2];
	int size;
	
	KD_node(point &X,int sz):x(X),ld(X),ru(X),size(sz){zuo=you=null;}
	KD_node(){}
	
	void check(){
		for(int i=0;i<K;i++){
			ld.d[i]=min(x.d[i],min(zuo->ld.d[i],you->ld.d[i]));
			ru.d[i]=max(x.d[i],max(zuo->ru.d[i],you->ru.d[i]));
		}
	}
	int dis_min(point &z){
		int re=0;
		for(int i=0;i<K;i++)
		if(z.d[i]<ld.d[i])re+=ld.d[i]-z.d[i];
		else if(z.d[i]>ru.d[i])re+=z.d[i]-ru.d[i];
		return re;
	}
	int dis_max(point &z){
		int re=0;
		for(int i=0;i<K;i++)
		re+=max(abs(z.d[i]-ld.d[i]),abs(z.d[i]-ru.d[i]));
		return re;
	}
};
void init(){
	null=new KD_node();null->size=0;
	for(int i=0;i<K;i++){
		null->ld.d[i]=inf;
		null->ru.d[i]=-inf;
	}
}
void build_KDtr(KD_node *&now,int l,int r,int CO=0)
{
	if(l>=r)return;
	int mid=l+r>>1;C=CO;
	nth_element(q+l,q+mid,q+r,cmp);
	now=new KD_node(q[mid],r-l);
	build_KDtr(now->zuo,l,mid,(CO+1)%K);
	build_KDtr(now->you,mid+1,r,(CO+1)%K);
	now->check();
}
void erase(KD_node *&now){
	if(now==null)return;
	q[++n]=now->x;
	erase(now->zuo);erase(now->you);
	delete now;
}
void rebuild(KD_node *&now){n=0;erase(now);build_KDtr(now,1,n+1);}
void add_node(KD_node *&now,point x,int CO=0,bool v=false)
{
	if(now==null){now=new KD_node(x,1);return;}
	now->size++;
	C=CO;int to=cmp(x,now->x)^1;
	bool tf=false;
	if(now->size*alpha<=now->ch[to]->size+1)tf=true;
	add_node(now->ch[to],x,(CO+1)%K,v|tf);
	if(!v&&tf)rebuild(now);
	now->check();
}
int ans;
void ask_min(KD_node *&now,point x)
{
	if(now==null)return;
	ans=min(ans,dis(now->x,x));
	int to=(now->zuo->dis_min(x)<now->you->dis_min(x))^1;
	ask_min(now->ch[to],x);
	if(now->ch[to^1]->dis_min(x)<ans)ask_min(now->ch[to^1],x);
}
void ask_max(KD_node *&now,point x)
{
	if(now==null)return;
	ans=max(ans,dis(now->x,x));
	int to=(now->zuo->dis_max(x)>now->you->dis_max(x))^1;
	ask_max(now->ch[to],x);
	if(now->ch[to^1]->dis_max(x)>ans)ask_max(now->ch[to^1],x);
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	for(int j=0;j<K;j++)scanf("%d",&q[i].d[j]);
	init();build_KDtr(root,1,n+1);
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int id;point x;
		scanf("%d",&id);
		for(int j=0;j<K;j++)scanf("%d",&x.d[j]);
		switch(id){
			case 0:add_node(root,x);break;
			case 1:ans=2*inf;ask_min(root,x);printf("%d\n",ans);break;
			case 2:ans=-2*inf;ask_max(root,x);printf("%d\n",ans);break;
		}
	}
}

你可能感兴趣的:(题解_杂)