1. 程式人生 > 其它 >#K-D Tree#洛谷 2093 [國家集訓隊]JZPFAR

#K-D Tree#洛谷 2093 [國家集訓隊]JZPFAR

題目

平面上有 \(n\) 個點。現在有 \(m\) 次詢問,每次給定一個點 \((px, py)\) 和一個整數 \(k\)
輸出 \(n\) 個點中離 \((px, py)\) 的距離第 \(k\) 大的點的標號。
如果有兩個(或多個)點距離 \((px, py)\) 相同,那麼認為標號較小的點距離較大。


分析

考慮用K-D Tree實現,維護區間橫縱座標最小值最大值,
至於第\(k\)遠點對開一個大小為\(k\)的小根堆初始為極小值,
每次將最小的替換出去即可,注意還要比較標號


程式碼

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <queue>
#define rr register
using namespace std;
const int N=200011;
typedef long long lll;
int ran,root,n,k;
struct Two{
	lll w; int rk;
	bool operator >(const Two &t)const{
	    return w>t.w||(w==t.w&&rk<t.rk);
	}
	bool operator <(const Two &t)const{
	    return w>t.w||(w==t.w&&rk<t.rk);
	}
};
priority_queue<Two>q;
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
inline void print(int ans){
	if (ans<0) putchar('-'),ans=-ans;
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline signed min(int a,int b){return a<b?a:b;}
inline lll max(lll a,lll b){return a>b?a:b;}
struct rec{
	int p[3];
	bool operator <(const rec &t)const{
	    return p[ran]<t.p[ran];
	}
};
inline lll SQR(lll x){return x*x;}
struct KD_Tree{
	int mn[N][2],mx[N][2],son[N][2]; rec p[N];
	inline void pup(int now){
		for (rr int i=0;i<2;++i){
			mn[now][i]=mx[now][i]=p[now].p[i];
			if (son[now][0]){
				mn[now][i]=min(mn[now][i],mn[son[now][0]][i]);
				mx[now][i]=max(mx[now][i],mx[son[now][0]][i]);
			}
			if (son[now][1]){
				mn[now][i]=min(mn[now][i],mn[son[now][1]][i]);
				mx[now][i]=max(mx[now][i],mx[son[now][1]][i]);
			}
		}
	}
	inline signed build(int l,int r,int Ran){
		if (l>r) return 0;
		rr int mid=(l+r)>>1;
		ran=Ran,nth_element(p+l,p+mid,p+1+r);
		son[mid][0]=build(l,mid-1,Ran^1);
		son[mid][1]=build(mid+1,r,Ran^1);
		pup(mid);
		return mid;
	}
	inline lll calc(int t,int x){
		return max(SQR(p[x].p[0]-mn[t][0]),SQR(p[x].p[0]-mx[t][0]))+max(SQR(p[x].p[1]-mn[t][1]),SQR(p[x].p[1]-mx[t][1]));
	}
	inline void query(int now,int x){
		rr Two t=(Two){SQR(p[x].p[0]-p[now].p[0])+SQR(p[x].p[1]-p[now].p[1]),p[now].p[2]};
		if (t>q.top()) q.pop(),q.push(t);
		rr Two c0=(Two){calc(son[now][0],x),0};
		rr Two c1=(Two){calc(son[now][1],x),0};
		if (son[now][0]&&son[now][1]){
			if (c0>c1&&c0>q.top()){
				query(son[now][0],x);
				if (c1>q.top()) query(son[now][1],x);
			}else if (c1>q.top()){
				query(son[now][1],x);
				if (c0>q.top()) query(son[now][0],x);
			}
		}else if (son[now][0]){
			if (c0>q.top()) query(son[now][0],x);
		}else if (son[now][1]){
			if (c1>q.top()) query(son[now][1],x);
		}
	}
}Tre;
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i) Tre.p[i].p[0]=iut(),Tre.p[i].p[1]=iut(),Tre.p[i].p[2]=i;
	root=Tre.build(1,n,0);
	for (rr int m=iut();m;--m){
		Tre.p[n+1].p[0]=iut(),Tre.p[n+1].p[1]=iut();
		while (!q.empty()) q.pop();
		for (rr int kth=iut();kth;--kth)
		    q.push((Two){-1000000000000000000ll,0});
		Tre.query(root,n+1),print(q.top().rk),putchar(10);
	}
	return 0;
}