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 31 1
2 3
2 1 2
1 3 3
2 4 2
Sample Output
12
正解: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; }
相关文章推荐
- Android 开发中的微技巧和小知识
- 预装64位Win8/8.1电脑安装64位Win7详细过程(单/双系统)
- 机器学习中过拟合问题分析及解决方法
- C++设计模式浅识装饰模式
- 1、wei-d-s嵌入式与PC区别,LED等的点亮以及调用C函数
- [HDOJ2586]How far away?(最近公共祖先, 离线tarjan, 并查集)
- iOS pushcontroller时自动隐藏tabbar
- 小技巧。
- 【SSH网上商城项目实战23】完成在线支付功能
- 实验五作业
- python 接口自动化测试--框架整改(五)
- GridView练习题
- Hibernate基本配置
- c语言实例之矩阵转置
- Hibernate继承映射
- Spark笔记:复杂RDD的API的理解(上)
- 机器学习常见算法总结(面试用)
- ng-repeat 中动态绑定ng-click 点击事件处理函数&动态改变ng-class
- hibernate关联映射与集合映射详解
- 安卓内存泄露分析整理