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
HINT
kdtree可以过
双倍经验hhh
此题似乎是kdtree的裸题= =
询问最坏是O(根号n)的,
就是插入可能最坏会O(n)吧,不行可以重构……但是其实还是会T的感觉。。
一开始网上很多题解的曼哈顿距离记录了max,min啥的不是很明白。
现在感觉就是一个启发式搜索。
维护当前切割的平面里面的二维坐标的最值,共4个。
然后搜索答案的时候可以判断两个平面内的dist,然后启发式地走哪一边。
感觉有点说不大清楚……max,min就是维护某一个切割平面内的坐标的最值。
画个图会更加明显一点的。
代码部分我不太行……
借鉴了orz 的代码。
调着调着就几乎和他一样了……(笑哭)
卡常?不存在的= =
#include<bits/stdc++.h>
#define ll long long
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;
}
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;
}