滑動視窗常用技巧總結
阿新 • • 發佈:2020-11-15
終於學會了kd樹不帶插入的,做了一下三維空間最近點對,記錄一下板子
這道題不知道為什麼不判斷兩座標相同答案為0的情況,加上之後就wa
#include <bits/stdc++.h> using namespace std; const int N=2e5+10; int n,root,D,K=3; struct Point{ double d[3]; friend bool operator < (const Point &a,const Point &b){ if(a.d[D]!=b.d[D]) return a.d[D]<b.d[D]; for(int i=0;i<K;i++) if(a.d[i]!=b.d[i]) return a.d[i]<b.d[i]; } }; Point p[N]; struct KDTree{ #define sqr(x) ((x)*(x)) Point p[N],minp[N],maxp[N]; int ls[N],rs[N]; void pushup(int id){ if(ls[id]) for(int i=0;i<K;i++) minp[id].d[i]=min(minp[id].d[i],minp[ls[id]].d[i]), maxp[id].d[i]=max(maxp[id].d[i],maxp[ls[id]].d[i]); if(rs[id]) for(int i=0;i<K;i++) minp[id].d[i]=min(minp[id].d[i],minp[rs[id]].d[i]), maxp[id].d[i]=max(maxp[id].d[i],maxp[rs[id]].d[i]); } void build(int &id,int l,int r,int dd){ D=dd; id=(l+r>>1); nth_element(p+l,p+id,p+r+1); minp[id]=p[id];maxp[id]=p[id]; if(id!=l) build(ls[id],l,id-1,(dd+1)%K); if(id!=r) build(rs[id],id+1,r,(dd+1)%K); pushup(id); } Point A; double ans; double getdis(int id){ double res=0; for(int i=0;i<K;i++){ if(A.d[i]<minp[id].d[i]) res+=sqr(minp[id].d[i]-A.d[i]); if(A.d[i]>maxp[id].d[i]) res+=sqr(maxp[id].d[i]-A.d[i]); } return res; } void ask(int id){ double d0=0; for(int i=0;i<K;i++) d0+=sqr(p[id].d[i]-A.d[i]); if(d0>0&&d0<ans) ans=d0; double dl=(ls[id])?getdis(ls[id]):1e18; double dr=(rs[id])?getdis(rs[id]):1e18; if(dl<dr) {if(dl<ans) ask(ls[id]); if(dr<ans) ask(rs[id]);} else {if(dr<ans) ask(rs[id]); if(dl<ans) ask(ls[id]);} } double ask(Point _A){ A=_A; ask(root); return ans; } }kdt; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=0;j<K;j++) scanf("%lf",&p[i].d[j]); memcpy(kdt.p,p,sizeof(p)); kdt.build(root,1,n,0); kdt.ans=1e18; for(int i=1;i<=n;i++) kdt.ask(p[i]); printf("%.3lf\n",sqrt(kdt.ans)); return 0; }