【BZOJ-2648&2716】SJY摆棋子&天使玩偶 KD Tree
2648: SJY摆棋子
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2459 Solved: 834
[Submit][Status][Discuss]
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
1 1
2 3
2 1 2
1 3 3
2 4 2
Sample Output
1
2
2
HINT
kdtree可以过
Source
2716: [Violet 3]天使玩偶
Time Limit: 80 Sec Memory Limit: 128 MBSubmit: 1098 Solved: 485
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
100 100 81 23 27 16 52 58 44 24 25 95 34 2 96 25 8 14 97 50 97 18 64 3 47 22 55 28 89 37 75 45 67 22 90 8 65 45 68 93 87 8 61 45 69 72 38 57 58 76 45 34 88 54 27 8 35 34 70 81 25 24 97 97 4 43 39 38 82 68 27 58 2 21 92 88 96 70 97 29 14 53 6 42 1 2 35 84 64 88 63 57 53 40 82 59 49 56 75 72 29 30 50 1 40 83 52 94 22 35 39 1 94 88 89 96 79 46 33 75 31 42 33 95 6 83 90 66 37 54 35 64 17 66 48 37 30 8 95 51 3 51 90 33 29 48 94 78 53 7 1 26 73 35 18 33 99 78 83 59 23 87 4 17 53 91 98 3 54 82 85 92 77 8 56 74 4 5 63 1 26 8 42 15 48 98 27 11 70 98 36 9 78 92 34 40 42 82 64 83 75 47 2 51 55 1 7 62 2 21 62 1 36 39 1 35 89 1 84 15 2 19 24 1 58 53 2 52 34 1 98 49 1 4 100 1 17 25 1 30 56 1 69 43 2 57 23 2 23 13 1 98 25 2 50 27 1 84 63 2 84 81 2 84 77 1 60 23 2 15 27 1 9 51 1 31 11 1 96 56 2 20 85 1 46 32 1 60 88 2 92 48 1 68 5 2 90 17 1 16 46 2 67 5 2 29 83 1 84 70 2 68 27 1 99 33 2 39 89 2 38 28 1 42 3 1 10 60 2 56 29 2 12 60 2 46 51 2 15 73 1 93 42 1 78 82 1 66 20 1 46 17 2 48 5 1 59 61 1 87 59 2 98 72 1 49 3 2 21 10 1 15 4 1 48 14 2 67 75 2 83 77 1 88 65 2 100 93 2 58 83 1 29 80 2 31 88 2 92 94 1 96 66 1 61 82 2 87 24 1 64 83 1 28 87 2 72 90 2 7 3 1 86 3 2 26 53 2 71 2 2 88 24 1 69 60 1 92 44 2 74 94 1 12 78 2 1 2 1 4 73 1 58 5 1 62 14 2 64 58 2 39 45 1 99 27 1 42 21 1 87 2 2 16 98 2 17 21 2 41 20 1 46 72 1 11 62 2 68 29 1 64 66 2 90 42 2 63 35 1 64 71
Sample Output
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
3 8 6 7 7 6 6 12 11 4 5 6 8 1 7 6 4 9 2 2 8 9 6 4 7 5 8 7 5 5 5 7 7 5 6 6 8 6 0 2 7 12 4 2 8 3 10
HINT
Source
Solution
双倍经验题,KD Tree模板题
KD Tree是一种切割多维空间的数据结构,主要用于多维空间信息的搜索(范围搜索和最近邻搜索)
大体上每层按照不同的维度进行左右建树,分开平面上的点,本质还是一颗平衡二叉树
效率大概是$O(log^{2}N)$的,比较暴力的做法
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define maxn 500010 int n,m,D; struct PointNode { int d[2],mn[2],mx[2],l,r; PointNode(int x=0,int y=0) {l=r=0;d[0]=x;d[1]=y;} bool operator < (const PointNode & A) const {return d[D]<A.d[D];} }p[maxn]; int dis(PointNode a,PointNode b) {return abs(a.d[0]-b.d[0])+abs(a.d[1]-b.d[1]);} struct K_DTreeNode { int rt,ans; PointNode Point,tree[maxn<<1]; void Update(int now) { for (int i=0; i<=1; i++) { if (tree[now].l) tree[now].mn[i]=min(tree[now].mn[i],tree[tree[now].l].mn[i]),tree[now].mx[i]=max(tree[now].mx[i],tree[tree[now].l].mx[i]); if (tree[now].r) tree[now].mn[i]=min(tree[now].mn[i],tree[tree[now].r].mn[i]),tree[now].mx[i]=max(tree[now].mx[i],tree[tree[now].r].mx[i]); } } int BuildTree(int l,int r,int dd) { D=dd; int mid=(l+r)>>1; nth_element(p+l,p+mid,p+r+1); tree[mid]=p[mid]; for (int i=0; i<=1; i++) tree[mid].mn[i]=tree[mid].mx[i]=tree[mid].d[i]; if (l<mid) tree[mid].l=BuildTree(l,mid-1,dd^1); if (r>mid) tree[mid].r=BuildTree(mid+1,r,dd^1); Update(mid); return mid; } void Insert(int now,int dd) { if (Point.d[dd]>=tree[now].d[dd]) if (tree[now].r) Insert(tree[now].r,dd^1); else { tree[now].r=++n; tree[n]=Point; for (int i=0; i<=1; i++) tree[n].mn[i]=tree[n].mx[i]=tree[n].d[i]; } else if (tree[now].l) Insert(tree[now].l,dd^1); else { tree[now].l=++n; tree[n]=Point; for (int i=0; i<=1; i++) tree[n].mn[i]=tree[n].mx[i]=tree[n].d[i]; } Update(now); } int dist(int p1,PointNode p) { int re=0; for (int i=0; i<=1; i++) re+=max(0,tree[p1].mn[i]-p.d[i]); for (int i=0; i<=1; i++) re+=max(0,p.d[i]-tree[p1].mx[i]); return re; } void Query(int now,int dd) { int dl,dr,d0; d0=dis(tree[now],Point); if (d0<ans) ans=d0; if (tree[now].l) dl=dist(tree[now].l,Point); else dl=0x7f7f7f7f; if (tree[now].r) dr=dist(tree[now].r,Point); else dr=0x7f7f7f7f; if (dl<dr) { if (dl<ans) Query(tree[now].l,dd^1); if (dr<ans) Query(tree[now].r,dd^1); } else { if (dr<ans) Query(tree[now].r,dd^1); if (dl<ans) Query(tree[now].l,dd^1); } } void insert(PointNode _p){Point=_p; Insert(rt,0);} void init(){rt=BuildTree(1,n,0);} int query(PointNode _p){Point=_p;ans=0x7fffffff; Query(rt,0); return ans;} }KDT; int main() { // freopen("angel.in","r",stdin); freopen("angel.out","w",stdout); n=read(),m=read(); for (int i=1; i<=n; i++) p[i].d[0]=read(),p[i].d[1]=read(); KDT.init(); for (int i=1; i<=m; i++) { int opt=read(),x=read(),y=read(); if (opt==1) KDT.insert(PointNode(x,y)); if (opt==2) printf("%d\n",KDT.query(PointNode(x,y))); } return 0; }
模板是参考的zky学长的,zky学长好神%%%
——It's a lonely path. Don't make it any lonelier than it has to be.