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 }