【BZOJ2648】【kd_tree】SJY摆棋子

Description
 
这天,SJY显得无聊。在家自己玩。在一个棋盘上,有N个黑色棋子。他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子。此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) 。现在给出N<=500000个初始棋子。和M<=500000个操作。对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离。同一个格子可能有多个棋子。
 
Input
 
第一行两个数 N M
以后M行,每行3个数 t x y
如果t=1 那么放下一个黑色棋子
如果t=2 那么放下一个白色棋子
Output
 
对于每个T=2 输出一个最小距离
 
Sample Input
 
2 3
 
1 1
 
2 3
 
2 1 2
 
1 3 3
 
2 4 2
 
Sample Output
1
 
2
HINT
 
 
kdtree可以过
【分析】
大家都知道kd_tree是什么吧,恩
就这样了..好吧,kd_tree一种空间树..看代码就知道了
  1 /*
  2 唐代李白
  3 《江夏别宋之悌》
  4 楚水清若空,遥将碧海通。人分千里外,兴在一杯中。
  5 谷鸟吟晴日,江猿啸晚风。平生不下泪,于此泣无穷.
  6 */
  7 #include <iostream>
  8 #include <cstdio>
  9 #include <algorithm>
 10 #include <cstring>
 11 #include <vector>
 12 #include <utility>
 13 #include <iomanip>
 14 #include <string>
 15 #include <cmath>
 16 #include <queue>
 17 #include <assert.h>
 18 #include <map>
 19 #include <ctime>
 20 #include <cstdlib>
 21 #include <stack>
 22 #include <set> 
 23 #define LOCAL
 24 const int INF = 0x7fffffff;
 25 const int MAXN = 100000  + 10;
 26 const int maxnode = 20000 * 2 + 200000 * 20;
 27 const int MAXM = 50000 + 10;
 28 const int MAX = 100000000;
 29 using namespace std;
 30 struct Node{//kd_tree 
 31    int d[2], l, r;
 32    int Max[2], Min[2];
 33 }t[1000000 + 10],tmp;
 34 
 35 int n,m,root,cmp_d;
 36 int k1, k2, k3, Ans;
 37 
 38 bool cmp(Node a, Node b){return (a.d[cmp_d]<b.d[cmp_d]) || ((a.d[cmp_d] == b.d[cmp_d]) && (a.d[!cmp_d] < b.d[!cmp_d]));}
 39 void update(int p){
 40      if (t[p].l){
 41         //左边最大的横坐标值 
 42         t[p].Max[0] = max(t[p].Max[0], t[t[p].l].Max[0]);
 43         t[p].Min[0] = min(t[p].Min[0], t[t[p].l].Min[0]);
 44         t[p].Max[1] = max(t[p].Max[1], t[t[p].l].Max[1]);
 45         t[p].Min[1] = min(t[p].Min[1], t[t[p].l].Min[1]);
 46      }
 47      if (t[p].r){
 48         t[p].Max[0] = max(t[p].Max[0], t[t[p].r].Max[0]);
 49         t[p].Min[0] = min(t[p].Min[0], t[t[p].r].Min[0]);
 50         t[p].Max[1] = max(t[p].Max[1], t[t[p].r].Max[1]);
 51         t[p].Min[1] = min(t[p].Min[1], t[t[p].r].Min[1]);
 52      }
 53      return;
 54 }
 55 //d是横竖切.. 
 56 int build(int l, int r, int D){
 57     int mid = (l + r) / 2;
 58     cmp_d = D;
 59     //按照cmp的比较顺序在l到r中找到第mid大的元素 
 60     nth_element(t + l + 1, t + mid + 1, t + r + 1, cmp);
 61     t[mid].Max[0] = t[mid].Min[0] = t[mid].d[0];
 62     t[mid].Max[1] = t[mid].Min[1] = t[mid].d[1];
 63     //递归建树 
 64     if (l != mid) t[mid].l = build(l, mid - 1, D ^ 1);
 65     if (r != mid) t[mid].r = build(mid + 1, r, D ^ 1);
 66     update(mid);
 67     return mid;
 68 }
 69 void insert(int now){
 70      int D = 0, p = root;//D还是表示方向
 71      while (1){
 72            //边下传边更新 
 73            t[p].Max[0] = max(t[p].Max[0], t[now].Max[0]);
 74            t[p].Min[0] = min(t[p].Min[0], t[now].Min[0]);
 75            t[p].Max[1] = max(t[p].Max[1], t[now].Max[1]);
 76            t[p].Min[1] = min(t[p].Min[1], t[now].Min[1]);
 77            //有没有点线段树的感觉.. 
 78            if (t[now].d[D] >= t[p].d[D]){
 79               if (t[p].r == 0){
 80                  t[p].r = now;
 81                  return;
 82               }else p = t[p].r;
 83            }else{
 84               if (t[p].l == 0){
 85                  t[p].l = now;
 86                  return;
 87               }else p = t[p].l;
 88            }
 89            D = D ^ 1; 
 90      } 
 91      return;
 92 }
 93 int ABS(int x) {return x < 0? -x : x;}
 94 //dist越小代表越趋近? 
 95 int dist(int p1, int px, int py){
 96     int dist = 0;
 97     if (px < t[p1].Min[0]) dist += t[p1].Min[0] - px;
 98     if (px > t[p1].Max[0]) dist += px - t[p1].Max[0];
 99     if (py < t[p1].Min[1]) dist += t[p1].Min[1] - py;
100     if (py > t[p1].Max[1]) dist += py - t[p1].Max[1];
101     return dist; 
102 }
103 void ask(int p){
104    int dl, dr, d0;
105    //哈密顿距离 
106    d0=ABS(t[p].d[0] - k2) + ABS(t[p].d[1] - k3);
107    if(d0 < Ans) Ans = d0;
108    if(t[p].l) dl = dist(t[p].l, k2, k3); else dl = 0x7f7f7f7f;
109    if(t[p].r) dr = dist(t[p].r, k2, k3); else dr = 0x7f7f7f7f;
110    //应该是一个启发式的过程。 
111    if(dl < dr){
112        if(dl < Ans) ask(t[p].l);
113        if(dr < Ans) ask(t[p].r);
114    }else{
115        if(dr < Ans) ask(t[p].r);
116        if(dl < Ans) ask(t[p].l);
117    }
118 }
119 
120 void init(){
121      //假设0为横坐标 
122      scanf("%d%d", &n, &m);
123      for (int i = 1; i <= n; i++)
124      scanf("%d%d", &t[i].d[0], &t[i].d[1]);
125      root = build(1, n, 0);
126 }
127 void work(){
128      for (int i = 1; i <= m ;i++){
129          scanf("%d%d%d", &k1, &k2, &k3);
130          if (k1 == 1){//黑棋 
131             ++n;
132             t[n].Max[0] = t[n].Min[0] = t[n].d[0] = k2;
133             t[n].Max[1] = t[n].Min[1] = t[n].d[1] = k3;
134             insert(n);
135          }else{
136             Ans = 0x7f7f7f7f;
137             ask(root);
138             printf("%d\n", Ans);
139          }
140      }
141 }
142 
143 int main(){
144    
145    init(); 
146    work();
147    return 0; 
148 }
View Code

 

 
posted @ 2015-03-18 09:23  TCtower  阅读(279)  评论(0编辑  收藏  举报