K遠點對(K-D Tree)

K遠點對

K-D Tree 真是優雅的暴力!開局建棵樹,剪枝刷題數!

題意:
給定二維平面上的NN個點,求第KK遠的無序點對。

思路:

  1. 別問我爲什麼想到用K-D Tree的,因爲是看了題解的。
  2. 本題沒有插入、刪除等高級操作,僅僅建樹和查詢,代碼簡潔。
  3. 進入正題:考慮暴力,暴力遍歷對於每個點而言能形成的所有點對,顯然複雜度爲O(n2)O(n^2),不可行,接下來考慮剪枝。
  4. 首先,K=min(100,n(n+1)2)K=min(100,\frac{n*(n+1)}{2}),所以先在小頂堆中插入2K2*K00,在後續暴力搜索前2K2*K大點對的過程中逐漸把它們poppop掉。
  5. 對這NN個點的每個點而言,都從K-D Tree的根節點往下遍歷,每到一個節點,先計算當前節點與這個點的距離,並更新小頂堆,然後進入到剪枝的關鍵步驟。
  6. 我們考慮每個節點的左右兒子,分別利用左右兒子的每個維度最大最小邊界來計算可能的最遠點,若當前子空間最遠的點都無法對小頂堆進行更新,則不需要進入這個空間了!
  7. 另一點剪枝:先遍歷左右子空間中最遠可能點更遠的子空間,這樣也許就不用再遍歷另外一個空間啦。
  8. 複雜度的話。。。還不會算,據說是O(n32)O(n^{\frac{3}{2}})

代碼

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章