如果给你平面内一些点,让你求距离某一个指定点最近的点,应该怎么办呢?

O(n)遍历!

但是,在遍历的过程中,我们发现有一些点是永远无法更新答案的。

如果我们把这些点按照一定顺序整理起来,省略对不必要点的遍历,是不是可以降低时间复杂度呢?

这样的话,我们要用到的工具就是KDtree。

 

KDtree本质上是一颗BST(二叉搜索树),只不过每一层按照不同的维度分割,也就是说,一层划分x,一层划分y,交替进行。大概就是这样:

优美的爆搜?KDtree学习

如果我们把他画在二维平面上的话,会发现KDtree实际上把一个矩形分割成了多个小矩形:

优美的爆搜?KDtree学习

(我是来盗图的QAQ)

更新答案时,采用邻域搜索的方式。我们发现我们查询的点落在了某个小矩形内,我们用这个小矩形内的点去更新答案。然后进行回溯,看一下周围的矩形有没有可能存在更优答案,如果不可能的话,就不用搜索它了。

这样下来的复杂度最优是O(logn),随机数据介于O(logn)~O(sqrt(n))之间。如果是特意构造的数据,可以卡到O(n)(比如精度要求实数,给你一个圆,让你查询距离圆心最近的点)。

然而一般情况下KDtree比较好写,在考场上可以比较经济地拿到大部分分数,还是值得学习的。

关于代码实现,自己YY即可。反正我是脑补出来的。

 

例题:

BZOJ2716/2648:

KDtree查曼哈顿距离的板子,由于数据比较水所以直接插入可过,不需要考虑平衡性的问题。

代码自己YY。我的仅供参考(虽然我自行胡编的代码没什么参考价值QAQ)。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cstdlib>
  6 using namespace std;
  7 const int maxn=1.5e6+1e2;
  8 const int inf=0x3f3f3f3f;
  9 
 10 int cmp,ans;
 11 struct Point {
 12     int d[2];
 13     friend bool operator < (const Point &a,const Point &b) {
 14         return a.d[cmp] < b.d[cmp];
 15     }
 16     int dis(const Point &o) const {
 17         int ret = 0;
 18         for(int i=0;i<2;i++)
 19             ret += abs( d[i] - o.d[i] );
 20         return ret;
 21     }
 22 }ps[maxn];
 23 
 24 int lson[maxn],rson[maxn],mi[maxn][2],mx[maxn][2];
 25 Point dv[maxn];
 26 int cnt;
 27 
 28 inline void update(int pos) {
 29     if( lson[pos] ) {
 30         for(int i=0;i<2;i++)
 31             mi[pos][i] = min( mi[pos][i] , mi[lson[pos]][i] ),
 32             mx[pos][i] = max( mx[pos][i] , mx[lson[pos]][i] );
 33     }
 34     if( rson[pos] ) {
 35         for(int i=0;i<2;i++)
 36             mi[pos][i] = min( mi[pos][i] , mi[rson[pos]][i] ),
 37             mx[pos][i] = max( mx[pos][i] , mx[rson[pos]][i] );
 38     }
 39 }
 40 inline void fill(int pos,const Point &p) {
 41     dv[pos] = p;
 42     for(int i=0;i<2;i++)
 43         mx[pos][i] = mi[pos][i] = p.d[i];
 44 }
 45 inline void build(int pos,int pl,int pr,int dir) {
 46     const int pmid = ( pl + pr ) >> 1;
 47     cmp = dir;
 48     nth_element(ps+pl,ps+pmid,ps+pr+1);
 49     fill(pos,ps[pmid]);
 50     if( pl < pmid ) build(lson[pos]=++cnt,pl,pmid-1,dir^1);
 51     if( pr > pmid ) build(rson[pos]=++cnt,pmid+1,pr,dir^1);
 52     update(pos);
 53 }
 54 inline void insert(int pos,Point np,int dir) {
 55     cmp = dir;
 56     if( np < dv[pos] ) {
 57         if( lson[pos] ) insert(lson[pos],np,dir^1);
 58         else {
 59             lson[pos] = ++cnt;
 60             fill(lson[pos],np);
 61         }
 62     } else {
 63         if( rson[pos] ) insert(rson[pos],np,dir^1);
 64         else {
 65             rson[pos] = ++cnt;
 66             fill(rson[pos],np);
 67         }
 68     }
 69     update(pos);
 70 }
 71 inline int dis(int pos,const Point &p) {
 72     int ret = 0;
 73     for(int i=0;i<2;i++)
 74         ret += max( p.d[i] - mx[pos][i] , 0 ) + max( mi[pos][i] - p.d[i] , 0 );
 75     return ret;
 76 }
 77 inline void query(int pos,const Point &p) {
 78     ans = min( ans , p.dis(dv[pos]) );
 79     int dl = lson[pos] ? dis(lson[pos],p) : inf;
 80     int dr = rson[pos] ? dis(rson[pos],p) : inf;
 81     if( dl < dr ) {
 82         if( dl < ans ) query(lson[pos],p);
 83         if( dr < ans ) query(rson[pos],p);
 84     } else {
 85         if( dr < ans ) query(rson[pos],p);
 86         if( dl < ans ) query(lson[pos],p);
 87     }
 88 }
 89 
 90 int main() {
 91     static int n,m;
 92     static Point p;
 93     
 94     scanf("%d%d",&n,&m);
 95     for(int i=1;i<=n;i++)
 96         scanf("%d%d",ps[i].d,ps[i].d+1);
 97     
 98     build(cnt=1,1,n,0);
 99     
100     for(int i=1,t;i<=m;i++) {
101         scanf("%d%d%d",&t,p.d,p.d+1);
102         if(t == 1) {
103             insert(1,p,0);
104         } else {
105             ans = inf;
106             query(1,p);
107             printf("%d\n",ans);
108         }
109     }
110     return 0;
111 }
View Code

相关文章:

  • 2021-03-31
  • 2021-10-27
  • 2021-12-02
  • 2022-01-13
  • 2022-01-16
  • 2022-12-23
  • 2021-12-17
  • 2021-07-01
猜你喜欢
  • 2021-05-27
  • 2021-11-01
  • 2021-09-12
  • 2021-06-04
  • 2022-12-23
  • 2021-07-18
  • 2021-08-12
相关资源
相似解决方案