学习了一下kd-tree,感觉在某些平面问题上具有独特的优势呢。。
kd-tree,就是用一直的n个点,将平面划分为n+1块,划分的方式:对于当前层,假设以x坐标为关键字,找到x坐标在中间的点p,然后将这个区间分成两块,一块的x坐标都比p小,另一块的x坐标都比p大;然后分别递归两块,但是那两块的关键字就是y坐标了。然后就一层x坐标一层y坐标递归下去,还是很直观的。(还有根据当前层的情况来决定以x坐标还是y坐标为关键字的,这里略去)
插入一个点,就找到这个点所在的块,然后根据父亲节点的关键字是横坐标还是纵坐标把所在的块分成两块。虽然这样最坏是O(N)级别的。(可能可用替罪羊树的暴力重构思想?不过我连替罪羊树都不会写这个怎么可能会写)
查询一个点p。一样还是找到它所在的块,然后首先ans=dist(p,该块对应的点)。然后每次回溯时,由于一个点把它所在的块分成了两份,而其中一份包含了p,我们先看一下以p为圆心,ans为半径画圆(欧几里得距离是圆,曼哈顿距离是一个正方形),看是否会和另一份相交,如果相交就查询另一份。由于有时会两个子节点都查询,所以不是O(logN)的,可能是O(N^0.5)?
然后这道题目就是裸题辣2333~\(≧▽≦)/~
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 1000005 #define inf 1000000000 using namespace std; int n,m,dim,rt,ans; int read(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } struct node{ int p[2],x[2],y[2]; }a[N]; bool cmp(node x,node y){ return x.p[dim]<y.p[dim]; } struct kd_tree{ int c[N][2]; node s[N],q; void maintain(int k){ int l=c[k][0],r=c[k][1],i; for (i=0; i<2; i++){ if (l){ s[k].x[i]=min(s[k].x[i],s[l].x[i]); s[k].y[i]=max(s[k].y[i],s[l].y[i]); } if (r){ s[k].x[i]=min(s[k].x[i],s[r].x[i]); s[k].y[i]=max(s[k].y[i],s[r].y[i]); } } } void add(int k,node t){ int i; for (i=0; i<2; i++) s[k].x[i]=s[k].y[i]=s[k].p[i]=t.p[i]; } int dist(node t,int k){ int tmp=0,i; for (i=0; i<2; i++) tmp+=max(0,s[k].x[i]-t.p[i]); for (i=0; i<2; i++) tmp+=max(0,t.p[i]-s[k].y[i]); return tmp; } void build(int &k,int l,int r,int now){ k=(l+r)>>1; dim=now; nth_element(a+l,a+k,a+r+1,cmp); add(k,a[k]); if (l<k) build(c[k][0],l,k-1,now^1); if (k<r) build(c[k][1],k+1,r,now^1); maintain(k); } void ins(int k,int now){ if (q.p[now]<s[k].p[now]) if (c[k][0]) ins(c[k][0],now^1); else{ c[k][0]=++n; add(n,q); } else if (c[k][1]) ins(c[k][1],now^1); else{ c[k][1]=++n; add(n,q); } maintain(k); } void qry(int k){ ans=min(ans,abs(s[k].p[0]-q.p[0])+abs(s[k].p[1]-q.p[1])); int dl=(c[k][0])?dist(q,c[k][0]):inf,dr=(c[k][1])?dist(q,c[k][1]):inf; if (dl<dr){ if (dl<ans) qry(c[k][0]); if (dr<ans) qry(c[k][1]); } else{ if (dr<ans) qry(c[k][1]); if (dl<ans) qry(c[k][0]); } } }kd; int main(){ n=read(); m=read(); int i; for (i=1; i<=n; i++) scanf("%d%d",&a[i].p[0],&a[i].p[1]); kd.build(rt,1,n,0); while (m--){ int k=read(); kd.q.p[0]=read(); kd.q.p[1]=read(); if (k==1) kd.ins(rt,0); else{ ans=inf; kd.qry(rt); printf("%d\n",ans); } } return 0; }
by lych
2016.3.5