zoukankan      html  css  js  c++  java
  • k-d 树

    k-d树简单地说就是暴力......

    暴力大法好...

    然而我不会.....

    k-d tree 用输入的点把一个超平面(呃,高维空间)划分成两部分.(k-d树的节点要把它的坐标存下来.)

    一个点管辖一个高维空间内的区域.比如说一个点v.

    选择v的第d个维度的坐标(不一定x-y-z-...-x-y-z...轮换.可以x-x-y-x-z-z-...),把管辖区域划分为两个部分.

    在这个管辖区域内的所有点,如果其第d维坐标比v的第d维坐标小,就划分到左子树,否则划到右子树(或者小于划到右子树,大于划到左子树.可以在同一棵树上混用,比如对于一个点用前者,对于另一个点用后者).

    在划分到左子树的点中选择一个点作为左子树的根,它的管辖范围就是它所在的v划分出来的两个部分的其中一个.

    右子树同理.

    构建的时间复杂度为 $O(n log n)$ (把输入的点随机打乱,一般不会影响树的功能.)

    如果要求在线插入,直接暴力,类似于二叉查找树,通过维度的坐标来判断应该往左子树走还是右子树走,然后走到空节点就说明新的节点应该占据这个空节点的位置.单次插入的最坏复杂度为 $O(n)$ 并且不保证均摊复杂度. 即,总的复杂度可能达到 $O(nk)$ , $k$ 是插入点数, $n$ 是0点数总和.

    如果像替罪羊树那样强行重构很不平衡(左右节点数之比约为2:1到4:1)的子树,那么可以达到在线 $O(nlogn)$. 重构方法就是把子树的所有点取出来,随机打乱,然后再插回去.

    感觉上,对于每一个点最好再用随机的方法做一个等号判断,即如果坐标相等应该被分到左边还是右边.这样应该可以完全防止插入操作被卡.

    对于k-d树的查询,一样是暴力搜索剪枝,具体情况具体分析.

    AC BZOJ 2648

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21 typedef long double ldb;
     22  
     23 using namespace std;
     24  
     25 inline int getint()
     26 {
     27     int res=0;
     28     char c=getchar();
     29     bool mi=false;
     30     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     31     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     32     return mi ? -res : res;
     33 }
     34 inline ll getll()
     35 {
     36     ll res=0;
     37     char c=getchar();
     38     bool mi=false;
     39     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     40     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     41     return mi ? -res : res;
     42 }
     43 
     44 //==============================================================================
     45 //==============================================================================
     46 //==============================================================================
     47 //==============================================================================
     48 
     49 
     50 const int INF=(1<<30)-1;
     51 
     52 struct node*nil;
     53 struct node
     54 {
     55     int p[2]; //location
     56     node*s[2]; //sub trees
     57     int l[2][2]; //first D:x/y second d:left(bottom)/right(top)
     58     
     59     node(){ }
     60     
     61     bool leftof(node*x,int d)
     62     { return p[d]<x->p[d]; }
     63     
     64     void update(node*f)
     65     {
     66         l[0][0]=min(l[0][0],f->p[0]);
     67         l[0][1]=max(l[0][1],f->p[0]);
     68         l[1][0]=min(l[1][0],f->p[1]);
     69         l[1][1]=max(l[1][1],f->p[1]);
     70     }
     71     
     72     int dist(int x,int y)
     73     {
     74         int xl=max(l[0][0]-x,0);
     75         int xr=max(x-l[0][1],0);
     76         int yl=max(l[1][0]-y,0);
     77         int yr=max(y-l[1][1],0);
     78         return max(xl,xr)+max(yl,yr);
     79     }
     80 };
     81 
     82 int ncnt=10000;
     83 node*nt;
     84 node*newnode(int x,int y)
     85 {
     86     if(ncnt==10000) { ncnt=0; nt=new node[10000]; }
     87     nt->p[0]=x; nt->p[1]=y;
     88      nt->s[0]=nt->s[1]=nil;
     89     nt->l[0][0]=nt->l[0][1]=nt->p[0];
     90     nt->l[1][0]=nt->l[1][1]=nt->p[1];
     91     ncnt++; return nt++;
     92 }
     93 
     94 node*root;
     95 
     96 void Insert(node*v)
     97 {
     98     if(root==nil)
     99     { root=v; return ; }
    100     
    101     node*x=root;
    102     node*t=nil;
    103     bool d=0;
    104     while(x!=nil)
    105     {
    106         d^=1;
    107         t=x;
    108         x->update(v);
    109         x=x->s[x->leftof(v,d)];
    110     }
    111     t->s[t->leftof(v,d)]=v;
    112 }
    113 
    114 int n,m;
    115 
    116 inline int abs(int p){ return (p&0x80000000) ? -p : p; }
    117 
    118 int qx,qy;
    119 inline int mad(node*x)
    120 { return abs(x->p[0]-qx)+abs(x->p[1]-qy); }
    121 
    122 int res;
    123 void Query(node*a)
    124 {
    125     res=min(res,mad(a)); 
    126     if(a->s[0]==a->s[1]) return ;
    127     int d[]={ a->s[0]==nil ? INF : a->s[0]->dist(qx,qy),
    128               a->s[1]==nil ? INF : a->s[1]->dist(qx,qy) };
    129     bool k=d[1]<d[0];
    130     Query(a->s[k]);
    131     if(d[!k]<res) Query(a->s[!k]);
    132 }
    133 
    134 int main()
    135 {
    136     nil=newnode(0,0);
    137     nil->s[0]=nil->s[1]=nil;
    138     nil->l[0][0]=nil->l[1][0]=-INF;
    139     nil->l[0][1]=nil->l[1][1]=INF;
    140     root=nil;
    141     
    142     n=getint();
    143     m=getint();
    144     for(int i=0;i<n;i++)
    145     { int x=getint(); int y=getint(); Insert(newnode(x,y)); }
    146     
    147     for(int d=0;d<m;d++)
    148     {
    149         int t=getint();
    150         qx=getint();
    151         qy=getint();
    152         if(t==1) Insert(newnode(qx,qy));
    153         else { res=INF; Query(root); printf("%d
    ",res); }
    154     }
    155     
    156     return 0;
    157 }
    View Code

    好慢好慢啊啊啊.......

    为什么我的程序就这么慢TAT

    对拍的时候运行时间明明是差不多的啊啊啊.....

    这道题没有卡插入,卡询问.....

    然后妥妥地T了好多遍.......

    询问的剪枝方法: 对于每个点,求出它所引领的子树(包括它自己)的所有点的外接矩形.

    如果查询点到这个矩形的距离比当前结果大,就不再深入搜索.(最优化剪枝).

    然后就可以A了.....

  • 相关阅读:
    668. Kth Smallest Number in Multiplication Table
    658. Find K Closest Elements
    483. Smallest Good Base
    475. Heaters
    454. 4Sum II
    441. Arranging Coins
    436. Find Right Interval
    410. Split Array Largest Sum
    392. Is Subsequence
    378. Kth Smallest Element in a Sorted Matrix
  • 原文地址:https://www.cnblogs.com/DragoonKiller/p/4584472.html
Copyright © 2011-2022 走看看