bzoj 2648: SJY摆棋子 (KD-tree)

2648: SJY摆棋子

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

[ Submit][ Status][ Discuss]

题解:KD-tree

KD-tree模板题

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 1000003
#define inf 2139062143
using namespace std;
struct data
{
	int d[2],mx[2],mn[2],l,r;
}tr[N];
int n,m,cmpd,x,y,opt,ans,root;
void update(int now)
{
	int l=tr[now].l; int r=tr[now].r;
	if (l) {
		tr[now].mx[0]=max(tr[now].mx[0],tr[l].mx[0]);
		tr[now].mx[1]=max(tr[now].mx[1],tr[l].mx[1]);
		tr[now].mn[1]=min(tr[now].mn[1],tr[l].mn[1]);
		tr[now].mn[0]=min(tr[now].mn[0],tr[l].mn[0]);
	}
	if (r) {
		tr[now].mx[0]=max(tr[now].mx[0],tr[r].mx[0]);
		tr[now].mx[1]=max(tr[now].mx[1],tr[r].mx[1]);
		tr[now].mn[1]=min(tr[now].mn[1],tr[r].mn[1]);
		tr[now].mn[0]=min(tr[now].mn[0],tr[r].mn[0]);
	}
}
int cmp(data a,data b)
{
	return a.d[cmpd]<b.d[cmpd]||a.d[cmpd]==b.d[cmpd]&&a.d[!cmpd]<b.d[!cmpd];
}
int build(int l,int r,int d)
{
	cmpd=d;
	int mid=(l+r)/2;
	nth_element(tr+l,tr+mid,tr+r+1,cmp);
	tr[mid].mx[0]=tr[mid].mn[0]=tr[mid].d[0];
	tr[mid].mx[1]=tr[mid].mn[1]=tr[mid].d[1];
	if (l!=mid) tr[mid].l=build(l,mid-1,d^1);
	if (r!=mid) tr[mid].r=build(mid+1,r,d^1);
	update(mid);
	return mid;
}
void insert(int now)
{
	int p=root; int d=0;
	while (true) {
		tr[p].mx[0]=max(tr[p].mx[0],tr[now].mx[0]);
		tr[p].mx[1]=max(tr[p].mx[1],tr[now].mx[1]);
		tr[p].mn[1]=min(tr[p].mn[1],tr[now].mn[1]);
		tr[p].mn[0]=min(tr[p].mn[0],tr[now].mn[0]);
		if (tr[now].d[d]>=tr[p].d[d])
		{
		 if (!tr[p].r) {
		 	tr[p].r=now; return;
		 }else p=tr[p].r;
	    }
	    else {
	    	if (!tr[p].l) {
	    		tr[p].l=now; return;
			}
			else p=tr[p].l;
		}
		d^=1;
	}
}
int dist(int now,int x,int y)
{
	int dis=0;
	if (x<tr[now].mn[0]) dis+=tr[now].mn[0]-x;
	if (x>tr[now].mx[0]) dis+=x-tr[now].mx[0];
	if (y<tr[now].mn[1]) dis+=tr[now].mn[1]-y;
	if (y>tr[now].mx[1]) dis+=y-tr[now].mx[1];
	return dis;
}
void query(int now)
{
	int dl,dr,d0;
	d0=abs(tr[now].d[0]-x)+abs(tr[now].d[1]-y);
	ans=min(ans,d0);
	if (tr[now].l) dl=dist(tr[now].l,x,y);
	else dl=inf;
	if (tr[now].r) dr=dist(tr[now].r,x,y);
	else dr=inf;
	if (dl<dr) {
		if (dl<ans) query(tr[now].l);
		if (dr<ans) query(tr[now].r);
	}
	else {
		if (dr<ans) query(tr[now].r);
		if (dl<ans) query(tr[now].l);
	}
}
int main()
{
	freopen("a.in","r",stdin);
	//freopen("my.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) scanf("%d%d",&tr[i].d[0],&tr[i].d[1]);
	root=build(1,n,0);
	for (int i=1;i<=m;i++) {
		scanf("%d%d%d",&opt,&x,&y);
		if (opt==1) {
			++n;
			tr[n].mx[0]=tr[n].mn[0]=tr[n].d[0]=x;
	        tr[n].mx[1]=tr[n].mn[1]=tr[n].d[1]=y;
	        insert(n);
		}
		else {
			ans=inf;
			query(root);
			printf("%d\n",ans);
		}
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值