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 }

 

posted @ 2016-05-20 22:32  ljh_2000  阅读(1902)  评论(3编辑  收藏  举报