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

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
#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]point[u].MAX[0]) dis+=x-point[u].MAX[0];
	if (ypoint[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

你可能感兴趣的:(kd-tree)