luogu P4357

トピックリンク

問題の意味

平面内にn個の点を与え、遠点kのディレクトリへのユークリッド距離を見つけます。

データ範囲

1 n個 1 E 5 1 k 100 , 2 31 1 \ルN \ルK \ le100、点\ le1e5,1 \ル2 ^ {31}座標

最初のkdツリーBST本質的に一つだけ、そして、ツリーI寸法一方向回転を構築し、具体的には第一の層は、ソート寸法、別のソート層と第二寸法、各層であります異次元の層。
各ノードは実用的な意味を有し、そして(また、本質的にBST)のようなバランスのとれたツリーがツリーはkdは。

このタイトルでは、最初の大きな距離は、プレK備蓄することができます。
そして、KD-ツリーからの照会
KD-ツリーへの最初の必要性が出て構築されました

	struct node{
		int x[2];
	}a[maxn];
	int opt;//轮换标记
	bool cmp(node a,node b){
		return a.x[opt]<b.x[opt];
	}
	void pushup(int x){
		for(int i=0;i<2;i++){mx[x][i]=mn[x][i]=d[x].x[i];}//mn,mx就是当前区间的最小,最大坐标
		if(lc){for(int i=0;i<2;i++){mx[x][i]=max(mx[x][i],mx[lc][i]);mn[x][i]=min(mn[x][i],mn[lc][i]);}}
		if(rc){for(int i=0;i<2;i++){mx[x][i]=max(mx[x][i],mx[rc][i]);mn[x][i]=min(mn[x][i],mn[rc][i]);}}
	}
	void build(int &x,int L,int R){
		if(L>R)return ;//这里L==R是可以的
		x=++cnt;
		opt=opt^1;int mid=L+R>>1;
		nth_element(a+L,a+mid,a+R+1,cmp);d[x]=a[mid];//建Kd-tree就是在当前区间中选出一个最中间的
		build(lc,L,mid-1);build(rc,mid+1,R);
		pushup(x);
	}

クエリが実際に存在座標、次いでkdツリー内の調査ににヒープの最小距離よりも大きい任意の距離(現在のk番目の最大)を得ている場合、それは置換してい

	inline ll pf(int x){
		return 1ll*x*x;
	}
	inline ll f(node a,node b){return pf(a.x[0]-b.x[0])+pf(a.x[1]-b.x[1]);}
	inline ll g(node a,int b){return max(pf(a.x[0]-mx[b][0]),pf(a.x[0]-mn[b][0]))+max(pf(a.x[1]-mx[b][1]),pf(a.x[1]-mn[b][1]));}
	inline void query(int x,node y){
		ll dl=-inf,dr=-inf;
		if(lc) dl=g(y,lc);//g表示一个坐标和一个节点的最大代价可能是多少
		if(rc) dr=g(y,rc);
		ll di=f(y,d[x]);//f表示具体的两个节点之间的举离
		if(-q.top()<di){q.pop();q.push(-di);}
		if(dl>dr){if(-q.top()<dl)query(lc,y);if(-q.top()<dr)query(rc,y);}//这里是剪枝如果当前第k大的距离大于子树中最大可能出现的距离,就不继续做了
		else {if(-q.top()<dr)query(rc,y);if(-q.top()<dl)query(lc,y);}
	}

クエリで見られるように、同様の性質の一種は、KD-木を剪定しました。複雑さは非常に保証されていません。

合計コード:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; 
const int maxn=1e5+5,inf=1<<30;
inline int read(){
	char c=getchar();int t=0,f=1;
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int n,k;
struct node{
	int x[2];
}a[maxn];
int opt;
bool cmp(node a,node b){
	return a.x[opt]<b.x[opt];
}
#define lc l[x]
#define rc r[x]
priority_queue<ll> q;
inline ll pf(int x){
	return 1ll*x*x;
}
struct tree{
	int mx[maxn<<1][2],mn[maxn<<1][2],l[maxn<<1],r[maxn<<1],cnt;
	node d[maxn<<1];
	void pushup(int x){
		for(int i=0;i<2;i++){mx[x][i]=mn[x][i]=d[x].x[i];}
		if(lc){for(int i=0;i<2;i++){mx[x][i]=max(mx[x][i],mx[lc][i]);mn[x][i]=min(mn[x][i],mn[lc][i]);}}
		if(rc){for(int i=0;i<2;i++){mx[x][i]=max(mx[x][i],mx[rc][i]);mn[x][i]=min(mn[x][i],mn[rc][i]);}}
	}
	void build(int &x,int L,int R){
		if(L>R)return ;x=++cnt;
		opt=opt^1;int mid=L+R>>1;
		nth_element(a+L,a+mid,a+R+1,cmp);d[x]=a[mid];
		build(lc,L,mid-1);build(rc,mid+1,R);
		pushup(x);
	}
	inline ll f(node a,node b){return pf(a.x[0]-b.x[0])+pf(a.x[1]-b.x[1]);}
	inline ll g(node a,int b){return max(pf(a.x[0]-mx[b][0]),pf(a.x[0]-mn[b][0]))+max(pf(a.x[1]-mx[b][1]),pf(a.x[1]-mn[b][1]));}
	inline void query(int x,node y){
		ll dl=-inf,dr=-inf;
		if(lc) dl=g(y,lc);
		if(rc) dr=g(y,rc);
		ll di=f(y,d[x]);
		if(-q.top()<di){q.pop();q.push(-di);}
		if(dl>dr){if(-q.top()<dl)query(lc,y);if(-q.top()<dr)query(rc,y);}
		else {if(-q.top()<dr)query(rc,y);if(-q.top()<dl)query(lc,y);}
	}
}t;
int main(){
	//freopen("luogu4357.in","r",stdin);
	//freopen("luogu4357.out","w",stdout);
	n=read(),k=read();
	for(int i=1;i<=n;i++){
		a[i].x[0]=read();a[i].x[1]=read();
	}
	for(int i=1;i<=2*k;i++){
		q.push(0);
	}
	t.build(t.l[0],1,n);
	for(int i=1;i<=n;i++)t.query(1,a[i]);
	printf("%lld\n",-q.top());
	return 0;
}
公開された62元の記事 ウォンの賞賛1 ビュー1004

おすすめ

転載: blog.csdn.net/wmhtxdy/article/details/103746872