首页 > 代码库 > bzoj2648 SJY摆棋子

bzoj2648 SJY摆棋子

2648: SJY摆棋子

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 1821  Solved: 591
[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

Sample Output


1
2

HINT

 

kdtree能够过

Source

鸣谢 孙嘉裕




K-D Tree第一题。唉,人生若仅仅如初见......

这道题考察的是K-D Tree在近期邻搜索方面的应用。非常显然,对于黑棋。增加到K-D Tree里。对于白棋,询问近期邻。

以下写一些自己关于这道题的理解吧:

  1.K-D Tree本质上是一种DFS的剪枝优化。

  2.每一层相应的区分维度是循环的。

因为这道题仅仅有两维,所以能够利用位运算的异或操作。

  3.在每一层的DFS中。有一个get函数,相当于预计了子区域距离那个点近期是多少,注意是预计。下一次的DFS就从dl和dr中较小的一边開始。感觉方法还是非常巧妙的。




#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 500005
#define inf 1000000000
using namespace std;
int n,m,root,D,ans;
struct data
{
	int d[2],mn[2],mx[2],l,r;
}p[maxn],t[maxn*2],tmp;
bool operator<(data a,data b)
{
	return a.d[D]<b.d[D];
}
inline 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;
}
inline int dis(data a,data b)
{
	return abs(a.d[0]-b.d[0])+abs(a.d[1]-b.d[1]);
}
inline void pushup(int k)
{
	int ls=t[k].l,rs=t[k].r;
	F(i,0,1)
	{
		if (ls)
		{
			t[k].mn[i]=min(t[k].mn[i],t[ls].mn[i]);
			t[k].mx[i]=max(t[k].mx[i],t[ls].mx[i]);
		}
		if (rs)
		{
			t[k].mn[i]=min(t[k].mn[i],t[rs].mn[i]);
			t[k].mx[i]=max(t[k].mx[i],t[rs].mx[i]);
		}
	}
}
inline int build(int l,int r,int now)
{
	D=now;
	int mid=(l+r)>>1;
	nth_element(p+l,p+mid,p+r+1);
	t[mid]=p[mid];
	F(i,0,1) t[mid].mn[i]=t[mid].mx[i]=t[mid].d[i];
	if (l<mid) t[mid].l=build(l,mid-1,now^1);
	if (mid<r) t[mid].r=build(mid+1,r,now^1);
	pushup(mid);
	return mid;
}
inline int get(int k,data x)
{
	int tmp=0;
	F(i,0,1) tmp+=max(0,t[k].mn[i]-x.d[i]);
	F(i,0,1) tmp+=max(0,x.d[i]-t[k].mx[i]);
	return tmp;
}
inline void insert(int k,int now)
{
	if (tmp.d[now]>=t[k].d[now])
	{
		if (t[k].r) insert(t[k].r,now^1);
		else
		{
			t[k].r=++n;t[n]=tmp;
			F(i,0,1) t[n].mn[i]=t[n].mx[i]=t[n].d[i];
		}
	}
	else
	{
		if (t[k].l) insert(t[k].l,now^1);
		else
		{
			t[k].l=++n;t[n]=tmp;
			F(i,0,1) t[n].mn[i]=t[n].mx[i]=t[n].d[i];
		}
	}
	pushup(k);
}
inline void query(int k,int now)
{
	int d,dl=inf,dr=inf;
	d=dis(t[k],tmp);
	ans=min(ans,d);
	if (t[k].l) dl=get(t[k].l,tmp);
	if (t[k].r) dr=get(t[k].r,tmp);
	if (dl<dr)
	{
		if (dl<ans) query(t[k].l,now^1);
		if (dr<ans) query(t[k].r,now^1);
	}
	else
	{
		if (dr<ans) query(t[k].r,now^1);
		if (dl<ans) query(t[k].l,now^1);
	}
}
int main()
{
	n=read();m=read();
	F(i,1,n){p[i].l=p[i].r=0;p[i].d[0]=read();p[i].d[1]=read();}
	root=build(1,n,0);
	tmp.l=tmp.r=0;
	while (m--)
	{
		int opt=read();tmp.d[0]=read();tmp.d[1]=read();
		if (opt==1) insert(root,0);
		else
		{
			ans=inf;
			query(root,0);
			printf("%d\n",ans);
		}
	}
	return 0;
}


bzoj2648 SJY摆棋子