BJWC 2014データ問題解決策

トピックポータル

主なアイデア:nnを与えるn点、mmありm操作、毎回:1.ポイントを追加します。2。ポイントコレクション内のクエリポイントに最も近いポイントからクエリポイントまでの距離を検索します。3。クエリポイントから最も遠いポイントからクエリポイントコレクション内のクエリポイントまでの距離を検索します。

回答

KDツリーの裸の質問。

最初に、各サブツリーに対応する行列を維持します。

最も近いポイントを見つけるための剪定は、次のとおりです。最初に、左右のサブツリーのクエリポイントに近いマトリックスに移動します。

最も遠い枝刈りを見つけます。同様に、最初に最も遠い行列に移動します。

コードは以下のように表示されます:

#include <cstdio>
#include <cstring>
#include <algorithm>
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;
		}
	}
}

おすすめ

転載: blog.csdn.net/a_forever_dream/article/details/108024737