【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

 

 

你可能感兴趣的:(tree)