BZOJ2648 SJY摆棋子
Description
Output
Sample Input
1 1
2 3
2 1 2
1 3 3
2 4 2
Sample Output
1
2
正解:kd-tree
解题报告:
大概题意是在一个棋盘上初始有一些黑棋子,接着要放一些黑白棋子,若放的是白棋子则回答离它最近的(曼哈顿距离)黑棋子的距离
参考了大神的博客:http://blog.sina.com.cn/s/blog_8d5d2f040101888r.html & http://blog.csdn.net/jiangshibiao/article/details/34144829
做这道题其实只是为了学kd-tree,据说是模板题,果然轻松AC了
先花了一个晚上学了kd-tree,然后就对着纸模拟了一下感觉会了,于是就顺手切掉了这道模板题。
大致思想感觉我看的那篇博客里面讲得比较清楚了,还是大概说一下吧。
这道题需要维护一个二维空间上的很多个点,然后查询离新加入的白点最近的黑点(曼哈顿距离)的距离,当然也可以直接加入一些黑点。
kd-tree有点像分治,也有点像线段树。
每次二分区间内点的横坐标或者纵坐标,然后以mid为界,两边分别处理。每个结点维护四个方向上的控制范围内的最值,画个图yy一下,所以保存四个值:控制范围内纵坐标的最大最小值,横坐标的最大最小值。再存一下这个点本身的横纵坐标。mid可以理解成这个区间的首领。
为了维护上述操作,我们需要用到nth_element这个STL,作用的话可以百度一下。
接着递归往下建就可以了,注意存一下每个结点控制区间下的子区间的控制节点(可以理解成子区间内的两个首领)。
所以我们可以轻松的build出kd-tree。
然后是插入,就是不断与当前结点的x,y按照现在的D(按横坐标还是纵坐标为第一关键字排序)比较之后决定往左还是往右插入,发现空位插进去就可以了。
查询的话有一些小技巧,我理解成是估算一下预计ans然后看先处理左边还是右边,往下更新就可以了。具体的看代码。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #ifdef WIN32 13 #define OT "%I64d" 14 #else 15 #define OT "%lld" 16 #endif 17 using namespace std; 18 typedef long long LL; 19 const int MAXN = 1000011; 20 const int inf = (1<<30); 21 int n,m; 22 int nowD; 23 int root; 24 int ans; 25 int ql,qr; 26 27 struct node{ 28 int Min[2],Max[2]; 29 int d[2]; 30 int l,r; 31 }t[MAXN*2]; 32 33 inline int getint() 34 { 35 int w=0,q=0; 36 char c=getchar(); 37 while((c<'0' || c>'9') && c!='-') c=getchar(); 38 if (c=='-') q=1, c=getchar(); 39 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 40 return q ? -w : w; 41 } 42 43 inline bool cmp(node q,node qq){ 44 if(q.d[nowD]==qq.d[nowD]) return q.d[!nowD]<qq.d[!nowD]; 45 return q.d[nowD]<qq.d[nowD]; 46 } 47 48 inline void kd_updata(int now){ 49 if(t[now].l) { 50 if(t[t[now].l].Max[0]>t[now].Max[0]) t[now].Max[0]=t[t[now].l].Max[0]; 51 if(t[t[now].l].Max[1]>t[now].Max[1]) t[now].Max[1]=t[t[now].l].Max[1]; 52 if(t[t[now].l].Min[0]<t[now].Min[0]) t[now].Min[0]=t[t[now].l].Min[0]; 53 if(t[t[now].l].Min[1]<t[now].Min[1]) t[now].Min[1]=t[t[now].l].Min[1]; 54 } 55 if(t[now].r) { 56 if(t[t[now].r].Max[0]>t[now].Max[0]) t[now].Max[0]=t[t[now].r].Max[0]; 57 if(t[t[now].r].Max[1]>t[now].Max[1]) t[now].Max[1]=t[t[now].r].Max[1]; 58 if(t[t[now].r].Min[0]<t[now].Min[0]) t[now].Min[0]=t[t[now].r].Min[0]; 59 if(t[t[now].r].Min[1]<t[now].Min[1]) t[now].Min[1]=t[t[now].r].Min[1]; 60 } 61 } 62 63 inline int kd_build(int l,int r,int D){ 64 int mid=(l+r)/2; 65 nowD=D; 66 nth_element(t+l+1,t+mid+1,t+r+1,cmp); 67 68 if(l!=mid) t[mid].l=kd_build(l,mid-1,!D); 69 if(r!=mid) t[mid].r=kd_build(mid+1,r,!D); 70 t[mid].Max[0]=t[mid].Min[0]=t[mid].d[0]; 71 t[mid].Max[1]=t[mid].Min[1]=t[mid].d[1]; 72 kd_updata(mid); 73 return mid; 74 } 75 76 inline int dist(int p){ 77 int dis=0; 78 if(ql<t[p].Min[0]) dis+=t[p].Min[0]-ql; 79 if(ql>t[p].Max[0]) dis+=ql-t[p].Max[0]; 80 if(qr<t[p].Min[1]) dis+=t[p].Min[1]-qr; 81 if(qr>t[p].Max[1]) dis+=qr-t[p].Max[1]; 82 return dis; 83 } 84 85 inline void kd_query(int p){ 86 int dl,dr,d0; 87 d0=abs(t[p].d[0]-ql)+abs(t[p].d[1]-qr); 88 if(d0<ans) ans=d0; 89 if(t[p].l) dl=dist(t[p].l); else dl=inf; 90 if(t[p].r) dr=dist(t[p].r); else dr=inf; 91 92 if(dl<dr) { 93 if(dl<ans) kd_query(t[p].l); 94 if(dr<ans) kd_query(t[p].r); 95 } 96 else{ 97 if(dr<ans) kd_query(t[p].r); 98 if(dl<ans) kd_query(t[p].l); 99 } 100 } 101 102 inline void kd_insert(int now){ 103 int p=root,D=0; 104 while(true){ 105 if(t[now].Max[0]>t[p].Max[0]) t[p].Max[0]=t[now].Max[0]; 106 if(t[now].Max[1]>t[p].Max[1]) t[p].Max[1]=t[now].Max[1]; 107 if(t[now].Min[0]<t[p].Min[0]) t[p].Min[0]=t[now].Min[0]; 108 if(t[now].Min[1]<t[p].Min[1]) t[p].Min[1]=t[now].Min[1]; 109 110 if(t[now].d[D]>=t[p].d[D]) { 111 if(!t[p].r){ 112 t[p].r=now; 113 return; 114 } 115 else p=t[p].r; 116 } 117 else{ 118 if(!t[p].l) { 119 t[p].l=now; 120 return ; 121 } 122 else p=t[p].l; 123 } 124 125 D=!D; 126 } 127 } 128 129 int main() 130 { 131 n=getint();m=getint(); 132 for(int i=1;i<=n;i++) t[i].d[0]=getint(),t[i].d[1]=getint(); 133 root=kd_build(1,n,0); 134 135 int x,y,z; 136 for(int i=1;i<=m;i++) { 137 x=getint(); y=getint(); z=getint(); 138 if(x==1) { 139 n++; 140 t[n].Max[0]=t[n].Min[0]=t[n].d[0]=y; t[n].Max[1]=t[n].Min[1]=t[n].d[1]=z; 141 kd_insert(n); 142 } 143 else{ 144 ans=inf; 145 ql=y,qr=z; 146 kd_query(root); 147 printf("%d\n",ans); 148 } 149 } 150 return 0; 151 }