BZOJ2648 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

 

正解: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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM