#K-D Tree#洛谷 2093 [國家集訓隊]JZPFAR
阿新 • • 發佈:2021-06-21
題目
平面上有 \(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; }