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了.....

  • 相关阅读:
    (五)Oracle学习笔记—— 视图
    (四)Oracle学习笔记—— 常见函数
    (三)Oracle学习笔记—— sql语句
    (二)Oracle学习笔记—— 序列
    mybatis部分版本异常invalid comparison: java.util.Date and java.lang.String
    spring 配置多数据源 (案例)
    spring 配置多数据源 (可行)
    使用Maven编译项目遇到——“maven编码gbk的不可映射字符”解决办法
    Java三大器之过滤器(Filter)的工作原理和代码演示
    Java三大器之监听器(Listener)的工作原理和代码演示
  • 原文地址:https://www.cnblogs.com/DragoonKiller/p/4584472.html
Copyright © 2011-2022 走看看