【kd-tree】专题总结

感谢orz神·小黑的指导

 

kd-tree就是用来计算若干维空间k近/远点的数(shou)据(suo)结(you)构(hua)

建树

假设题目是k维的点

第deep层就是用deep%k+1维把所有点分为两块

取deep%k+1维中位数的点做为当前子树的根节点

再把该维比这个点小的点扔到左子树 比这个点大的扔到右子树 递归处理

详见代码

 1 void Sort(ll l,ll r,ll k){ cmpp=k; sort(kd+l,kd+r+1,cmp); }

 2 ll build(ll l,ll r,ll deep){

 3     if (l==r){

 4         kd[l].lc=kd[r].rc=0;

 5         return l;

 6     }

 7     Sort(l,r,deep);

 8     ll mid=(l+r)/2;

 9     if (l<mid) kd[mid].lc=build(l,mid-1,deep%k+1);

10     else kd[mid].lc=0;

11     if (mid<r) kd[mid].rc=build(mid+1,r,deep%k+1);

12     else kd[mid].rc=0;

13     return mid;

14 }

 

查询

询问离点S的前m近点 说它是搜索优化就是因为这里- -

维护大根堆记录答案 当元素个数小于m时直接push

反正判断有木有 比最大值小 有就pop再push

当搜索当t点是先用该点到S的距离维护堆

再判断如果S的deep%k+1维 比t点该维小就先搜索左子树 否则搜索右子树

搜索完一颗子树后 判断如果S到t点deep%k+1维的距离就≥ans显然继续搜索没用 就不继续搜索 否则搜索另一颗子树

代码

 1 void push(ll t){

 2     ll dis=getdis(S,poi[t]);

 3     if (size==m){

 4         if (dis>que.top().dis) return;

 5         else{

 6             que.pop();

 7             que.push(info(dis,t));

 8         }

 9     }else{

10         ++size;

11         que.push(info(dis,t));

12     }

13 }

14 void makeans(ll t,ll deep){

15     if (!t) return;

16     push(kd[t].t);

17     if (S.d[deep]<=kd[t].p.d[deep]){

18         makeans(kd[t].lc,deep%k+1);

19         if (size<m || que.top().dis>sqr(S.d[deep]-kd[t].p.d[deep])) makeans(kd[t].rc,deep%k+1);

20     }else{

21         makeans(kd[t].rc,deep%k+1);

22         if (size<m || que.top().dis>sqr(S.d[deep]-kd[t].p.d[deep])) makeans(kd[t].lc,deep%k+1);

23     }

24 }

 

最远点

这里讲的都是m近点- - 

如果是m远点其实是差不多的 只是维护的东西不太一样

需要维护每维的min和max

询问的时候基本同理yy下即可

 

求k位距离S的m近点代码

  1 #include <cstdio>

  2 #include <algorithm>

  3 #include <queue>

  4 typedef long long ll;

  5 using namespace std;

  6 const ll N=50001;

  7 struct inpo{

  8     ll d[6];

  9 }poi[N],S,ans[11];

 10 struct inkd{

 11     ll t,lc,rc;

 12     inpo p;

 13     inkd(const ll a=0,const ll b=0,const ll c=0):

 14         t(a),lc(b),rc(c){}

 15 }kd[N];

 16 struct info{

 17     ll dis,t;

 18     info(const ll a=0,const ll b=0):

 19         dis(a),t(b){}

 20 };

 21 priority_queue <info> que;

 22 ll root,n,k,m,t,cmpp,size;

 23 inline bool operator <(info a,info b){ return a.dis<b.dis; }

 24 inline bool cmp(inkd a,inkd b){ return a.p.d[cmpp]<b.p.d[cmpp]; }

 25 void Sort(ll l,ll r,ll k){ cmpp=k; sort(kd+l,kd+r+1,cmp); }

 26 ll sqr(ll x){ return x*x; }

 27 ll getdis(inpo a,inpo b){

 28     ll res=0;

 29     for (ll i=1;i<=k;i++) res+=sqr(a.d[i]-b.d[i]);

 30     return res;

 31 }

 32 ll build(ll l,ll r,ll deep){

 33     if (l==r){

 34         kd[l].lc=kd[r].rc=0;

 35         return l;

 36     }

 37     Sort(l,r,deep);

 38     ll mid=(l+r)/2;

 39     if (l<mid) kd[mid].lc=build(l,mid-1,deep%k+1);

 40     else kd[mid].lc=0;

 41     if (mid<r) kd[mid].rc=build(mid+1,r,deep%k+1);

 42     else kd[mid].rc=0;

 43     return mid;

 44 }

 45 void push(ll t){

 46     ll dis=getdis(S,poi[t]);

 47     if (size==m){

 48         if (dis>que.top().dis) return;

 49         else{

 50             que.pop();

 51             que.push(info(dis,t));

 52         }

 53     }else{

 54         ++size;

 55         que.push(info(dis,t));

 56     }

 57 }

 58 void makeans(ll t,ll deep){

 59     if (!t) return;

 60     push(kd[t].t);

 61     if (S.d[deep]<=kd[t].p.d[deep]){

 62         makeans(kd[t].lc,deep%k+1);

 63         if (size<m || que.top().dis>sqr(S.d[deep]-kd[t].p.d[deep])) makeans(kd[t].rc,deep%k+1);

 64     }else{

 65         makeans(kd[t].rc,deep%k+1);

 66         if (size<m || que.top().dis>sqr(S.d[deep]-kd[t].p.d[deep])) makeans(kd[t].lc,deep%k+1);

 67     }

 68 }

 69 int main(){

 70     freopen("hdu4347.in","r",stdin);

 71     freopen("hdu4347.out","w",stdout);

 72     while (~scanf("%I64d%I64d",&n,&k)){

 73         for (ll i=1;i<=n;i++){

 74             for (ll j=1;j<=k;j++) scanf("%I64d",&poi[i].d[j]);

 75             kd[i].t=i,kd[i].p=poi[i];

 76         }

 77         root=build(1,n,1);

 78         scanf("%I64d",&t);

 79         for (;t;t--){

 80             size=0;

 81             for (ll i=1;i<=k;i++) scanf("%I64d",&S.d[i]);

 82             scanf("%I64d",&m);

 83             printf("the closest %I64d points are:\n",m);

 84             makeans(root,1);

 85             for (ll i=1;i<=m;i++){

 86                 ans[i]=poi[que.top().t];

 87                 que.pop();

 88             }

 89             for (ll i=m;i;i--){

 90                 for (ll j=1;j<=k;j++){

 91                     printf("%I64d",ans[i].d[j]);

 92                     if (j<k) printf(" ");

 93                 }

 94                 puts("");

 95             }

 96         }

 97     }

 98     fclose(stdin);

 99     fclose(stdout);

100 }
View Code

 

你可能感兴趣的:(tree)