K遠點對
K-D Tree 真是優雅的暴力!開局建棵樹,剪枝刷題數!
題意:
給定二維平面上的個點,求第遠的無序點對。
思路:
- 別問我爲什麼想到用K-D Tree的,因爲是看了題解的。
- 本題沒有插入、刪除等高級操作,僅僅建樹和查詢,代碼簡潔。
- 進入正題:考慮暴力,暴力遍歷對於每個點而言能形成的所有點對,顯然複雜度爲,不可行,接下來考慮剪枝。
- 首先,,所以先在小頂堆中插入個,在後續暴力搜索前大點對的過程中逐漸把它們掉。
- 對這個點的每個點而言,都從K-D Tree的根節點往下遍歷,每到一個節點,先計算當前節點與這個點的距離,並更新小頂堆,然後進入到剪枝的關鍵步驟。
- 我們考慮每個節點的左右兒子,分別利用左右兒子的每個維度最大最小邊界來計算可能的最遠點,若當前子空間最遠的點都無法對小頂堆進行更新,則不需要進入這個空間了!
- 另一點剪枝:先遍歷左右子空間中最遠可能點更遠的子空間,這樣也許就不用再遍歷另外一個空間啦。
- 複雜度的話。。。還不會算,據說是。
代碼
#include "bits/stdc++.h"
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-7;
int N, K, rt, tot, Dim;
int ls[maxn], rs[maxn];
ll mi[maxn][2], mx[maxn][2];
priority_queue<ll,vector<ll>,greater<ll> > q;
struct P{
ll x[2];
friend bool operator < (const P &a, const P &b) {
return a.x[Dim]<b.x[Dim];
}
friend inline ll cal(const P &a, const P &b) {
return (a.x[0]-b.x[0])*(a.x[0]-b.x[0])+(a.x[1]-b.x[1])*(a.x[1]-b.x[1]);
}
inline ll cal(const ll mi[2], const ll mx[2]) {
ll d1=max(abs(x[0]-mi[0]),abs(x[0]-mx[0]));
ll d2=max(abs(x[1]-mi[1]),abs(x[1]-mx[1]));
return d1*d1+d2*d2;
}
}p[maxn], tmp[maxn];
inline void Min(ll &a, ll b) { if(a>b) a=b; }
inline void Max(ll &a, ll b) { if(a<b) a=b; }
void push_up(int now) {
for(int i=0; i<2; ++i) {
mi[now][i]=mx[now][i]=p[now].x[i];
if(ls[now]) Min(mi[now][i],mi[ls[now]][i]), Max(mx[now][i],mx[ls[now]][i]);
if(rs[now]) Min(mi[now][i],mi[rs[now]][i]), Max(mx[now][i],mx[rs[now]][i]);
}
}
void build(int l, int r, int dim, int &now) {
if(l>r) return;
now=++tot;
int m=(l+r)/2;
Dim=dim; nth_element(tmp+l,tmp+m,tmp+r+1); p[now]=tmp[m];
build(l,m-1,dim^1,ls[now]); build(m+1,r,dim^1,rs[now]);
push_up(now);
}
void query(P &a, int now) {
ll t=cal(a,p[now]), lt=0, rt=0;
if(t>q.top()) q.pop(), q.push(t);
if(ls[now]) lt=a.cal(mi[ls[now]],mx[ls[now]]);
if(rs[now]) rt=a.cal(mi[rs[now]],mx[rs[now]]);
if(lt>rt) {
if(lt>q.top()) query(a,ls[now]);
if(rt>q.top()) query(a,rs[now]);
}
else {
if(rt>q.top()) query(a,rs[now]);
if(lt>q.top()) query(a,ls[now]);
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin>>N>>K;
for(int i=1; i<=N; ++i) cin>>tmp[i].x[0]>>tmp[i].x[1];
build(1,N,0,rt);
for(int i=1; i<=2*K; ++i) q.push(0);
for(int i=1; i<=N; ++i) query(tmp[i],rt);
cout<<q.top()<<endl;
}