您的位置:首页 > 其它

BZOJ2648 SJY摆棋子

2016-05-20 22:32 323 查看

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然后看先处理左边还是右边,往下更新就可以了。具体的看代码。

//It is made by jump~
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#ifdef WIN32
#define OT "%I64d"
#else
#define OT "%lld"
#endif
using namespace std;
typedef long long LL;
const int MAXN = 1000011;
const int inf = (1<<30);
int n,m;
int nowD;
int root;
int ans;
int ql,qr;

struct node{
int Min[2],Max[2];
int d[2];
int l,r;
}t[MAXN*2];

inline int getint()
{
int w=0,q=0;
char c=getchar();
while((c<'0' || c>'9') && c!='-') c=getchar();
if (c=='-')  q=1, c=getchar();
while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
return q ? -w : w;
}

inline bool cmp(node q,node qq){
if(q.d[nowD]==qq.d[nowD]) return q.d[!nowD]<qq.d[!nowD];
return q.d[nowD]<qq.d[nowD];
}

inline void kd_updata(int now){
if(t[now].l) {
if(t[t[now].l].Max[0]>t[now].Max[0]) t[now].Max[0]=t[t[now].l].Max[0];
if(t[t[now].l].Max[1]>t[now].Max[1]) t[now].Max[1]=t[t[now].l].Max[1];
if(t[t[now].l].Min[0]<t[now].Min[0]) t[now].Min[0]=t[t[now].l].Min[0];
if(t[t[now].l].Min[1]<t[now].Min[1]) t[now].Min[1]=t[t[now].l].Min[1];
}
if(t[now].r) {
if(t[t[now].r].Max[0]>t[now].Max[0]) t[now].Max[0]=t[t[now].r].Max[0];
if(t[t[now].r].Max[1]>t[now].Max[1]) t[now].Max[1]=t[t[now].r].Max[1];
if(t[t[now].r].Min[0]<t[now].Min[0]) t[now].Min[0]=t[t[now].r].Min[0];
if(t[t[now].r].Min[1]<t[now].Min[1]) t[now].Min[1]=t[t[now].r].Min[1];
}
}

inline int kd_build(int l,int r,int D){
int mid=(l+r)/2;
nowD=D;
nth_element(t+l+1,t+mid+1,t+r+1,cmp);

if(l!=mid) t[mid].l=kd_build(l,mid-1,!D);
if(r!=mid) t[mid].r=kd_build(mid+1,r,!D);
t[mid].Max[0]=t[mid].Min[0]=t[mid].d[0];
t[mid].Max[1]=t[mid].Min[1]=t[mid].d[1];
kd_updata(mid);
return mid;
}

inline int dist(int p){
int dis=0;
if(ql<t[p].Min[0]) dis+=t[p].Min[0]-ql;
if(ql>t[p].Max[0]) dis+=ql-t[p].Max[0];
if(qr<t[p].Min[1]) dis+=t[p].Min[1]-qr;
if(qr>t[p].Max[1]) dis+=qr-t[p].Max[1];
return dis;
}

inline void kd_query(int p){
int dl,dr,d0;
d0=abs(t[p].d[0]-ql)+abs(t[p].d[1]-qr);
if(d0<ans) ans=d0;
if(t[p].l) dl=dist(t[p].l); else dl=inf;
if(t[p].r) dr=dist(t[p].r); else dr=inf;

if(dl<dr) {
if(dl<ans) kd_query(t[p].l);
if(dr<ans) kd_query(t[p].r);
}
else{
if(dr<ans) kd_query(t[p].r);
if(dl<ans) kd_query(t[p].l);
}
}

inline void kd_insert(int now){
int p=root,D=0;
while(true){
if(t[now].Max[0]>t[p].Max[0]) t[p].Max[0]=t[now].Max[0];
if(t[now].Max[1]>t[p].Max[1]) t[p].Max[1]=t[now].Max[1];
if(t[now].Min[0]<t[p].Min[0]) t[p].Min[0]=t[now].Min[0];
if(t[now].Min[1]<t[p].Min[1]) t[p].Min[1]=t[now].Min[1];

if(t[now].d[D]>=t[p].d[D]) {
if(!t[p].r){
t[p].r=now;
return;
}
else p=t[p].r;
}
else{
if(!t[p].l) {
t[p].l=now;
return ;
}
else p=t[p].l;
}

D=!D;
}
}

int main()
{
n=getint();m=getint();
for(int i=1;i<=n;i++) t[i].d[0]=getint(),t[i].d[1]=getint();
root=kd_build(1,n,0);

int x,y,z;
for(int i=1;i<=m;i++) {
x=getint(); y=getint(); z=getint();
if(x==1) {
n++;
t
.Max[0]=t
.Min[0]=t
.d[0]=y; t
.Max[1]=t
.Min[1]=t
.d[1]=z;
kd_insert(n);
}
else{
ans=inf;
ql=y,qr=z;
kd_query(root);
printf("%d\n",ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: