BZOJ 2648/2716 SJY摆棋子/[Violet 3]天使玩偶 kd tree

来源:互联网 发布:mac基于linux还是unix 编辑:程序博客网 时间:2024/05/22 03:16

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

HINT

 

kdtree可以过






传送门
双倍经验hhh
此题似乎是kdtree的裸题= =
询问最坏是O(根号n)的,
就是插入可能最坏会O(n)吧,不行可以重构……但是其实还是会T的感觉。。

一开始网上很多题解的曼哈顿距离记录了max,min啥的不是很明白。
现在感觉就是一个启发式搜索。
维护当前切割的平面里面的二维坐标的最值,共4个。
然后搜索答案的时候可以判断两个平面内的dist,然后启发式地走哪一边。
感觉有点说不大清楚……max,min就是维护某一个切割平面内的坐标的最值。
画个图会更加明显一点的。

代码部分我不太行……
借鉴了orz的代码。
调着调着就几乎和他一样了……(笑哭)

卡常?不存在的= =



#include<bits/stdc++.h>#define ll long longusing 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;}const int N=500005,inf=2000000000;int n,m,t,ans,root;struct POINT{int Dim[2],MAX[2],MIN[2],l,r;}point[N+N],T;bool cmp(POINT x,POINT y){return x.Dim[t]<y.Dim[t];}int dist(int u,int x,int y){int dis=0;if (x<point[u].MIN[0]) dis+=point[u].MIN[0]-x;if (x>point[u].MAX[0]) dis+=x-point[u].MAX[0];if (y<point[u].MIN[1]) dis+=point[u].MIN[1]-y;if (y>point[u].MAX[1]) dis+=y-point[u].MAX[1];return dis;}void up(int u){if (point[u].l){point[u].MAX[0]=max(point[u].MAX[0],point[point[u].l].MAX[0]);point[u].MAX[1]=max(point[u].MAX[1],point[point[u].l].MAX[1]);point[u].MIN[0]=min(point[u].MIN[0],point[point[u].l].MIN[0]);point[u].MIN[1]=min(point[u].MIN[1],point[point[u].l].MIN[1]);}if (point[u].r){point[u].MAX[0]=max(point[u].MAX[0],point[point[u].r].MAX[0]);point[u].MAX[1]=max(point[u].MAX[1],point[point[u].r].MAX[1]);point[u].MIN[0]=min(point[u].MIN[0],point[point[u].r].MIN[0]);point[u].MIN[1]=min(point[u].MIN[1],point[point[u].r].MIN[1]);}}int build(int L,int R,int now){int mid=(L+R)>>1;t=now;nth_element(point+L,point+mid,point+R+1,cmp);point[mid].MAX[0]=point[mid].MIN[0]=point[mid].Dim[0];point[mid].MAX[1]=point[mid].MIN[1]=point[mid].Dim[1];if (L!=mid) point[mid].l=build(L,mid-1,now^1);if (R!=mid) point[mid].r=build(mid+1,R,now^1);up(mid);return mid;}void insert(int id){int now=0,p=root;while (1){point[p].MAX[0]=max(point[id].MAX[0],point[p].MAX[0]);point[p].MAX[1]=max(point[id].MAX[1],point[p].MAX[1]);point[p].MIN[0]=min(point[id].MIN[0],point[p].MIN[0]);point[p].MIN[1]=min(point[id].MIN[1],point[p].MIN[1]);if (point[id].Dim[now]<=point[p].Dim[now])if (!point[p].l){point[p].l=id;return;} else p=point[p].l; else if (!point[p].r){point[p].r=id;return;} else p=point[p].r;now^=1;}}void query(int id){int d0,dl,dr;d0=abs(T.Dim[0]-point[id].Dim[0])+abs(T.Dim[1]-point[id].Dim[1]);if (ans>d0) ans=d0;if (point[id].l) dl=dist(point[id].l,T.Dim[0],T.Dim[1]); else dl=inf;if (point[id].r) dr=dist(point[id].r,T.Dim[0],T.Dim[1]); else dr=inf;if (dl<dr){if (dl<ans) query(point[id].l);if (dr<ans) query(point[id].r);} else{if (dr<ans) query(point[id].r);if (dl<ans) query(point[id].l);}}int main(){n=read(),m=read();for (int i=1;i<=n;i++)point[i].Dim[0]=read(),point[i].Dim[1]=read();root=build(1,n,0);while (m--){int opt=read();T.Dim[0]=read(),T.Dim[1]=read();if (opt==1){n++;point[n].MAX[0]=point[n].MIN[0]=point[n].Dim[0]=T.Dim[0];point[n].MAX[1]=point[n].MIN[1]=point[n].Dim[1]=T.Dim[1];insert(n);} else{ans=inf,query(root);printf("%d\n",ans);}}return 0;}

阅读全文
0 0
原创粉丝点击