HYSBZ2648-SJY摆棋子(kd-tree)

26 篇文章 0 订阅
8 篇文章 0 订阅

SJY摆棋子

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



解题思路:kd-tree


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cctype>
#include <map>
#include <cmath>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>

using namespace std;

#define LL long long
const int INF = 0x3f3f3f3f;
const int N = 2000000 + 5;
const int demension = 2;//二维

struct node
{
	int pos[demension];
	int ma[demension], mi[demension];
	int l, r;
}a[N], x;
int cmpDem;//以第cmpDem维作比较
int root, op, n, q, ans;

bool cmp(const node &a, const node&b)
{
	if (a.pos[cmpDem] != b.pos[cmpDem]) return a.pos[cmpDem] < b.pos[cmpDem];
	else return a.pos[!cmpDem] < b.pos[!cmpDem];
}

void Merge(int k)
{
	for (int i = 0; i < demension; i++)
	{
		if (a[k].l)
		{
			a[k].ma[i] = max(a[k].ma[i], a[a[k].l].ma[i]);
			a[k].mi[i] = min(a[k].mi[i], a[a[k].l].mi[i]);
		}
		if (a[k].r)
		{
			a[k].ma[i] = max(a[k].ma[i], a[a[k].r].ma[i]);
			a[k].mi[i] = min(a[k].mi[i], a[a[k].r].mi[i]);
		}
	}
}

void Merge(int x, int y)
{
	a[x].ma[0] = max(a[x].ma[0], a[y].ma[0]);
	a[x].ma[1] = max(a[x].ma[1], a[y].ma[1]);
	a[x].mi[0] = min(a[x].mi[0], a[y].mi[0]);
	a[x].mi[1] = min(a[x].mi[1], a[y].mi[1]);
}

int dis(int k)
{
	int dis = 0;
	for (int i = 0; i < demension; i++)
	{
		if (x.pos[i] < a[k].mi[i]) dis += (a[k].mi[i] - x.pos[i]);
		if (x.pos[i] > a[k].ma[i]) dis += (x.pos[i] - a[k].ma[i]);
	}
	return dis;
}

int build(int l, int r, int k)
{
	if (l > r) return 0;
	int mid = (l + r) / 2;
	//以第mid个元素为中心排序
	cmpDem = k;
	nth_element(a + l, a + mid, a + r + 1, cmp);
	//左右子树
	a[mid].l = build(l, mid - 1, k ^ 1);
	a[mid].r = build(mid + 1, r, k ^ 1);
	Merge(mid);
	return mid;
}

int update(int k, int p)
{
	if (!k) return n;
	Merge(k, n);
	if (a[k].pos[p] > a[n].pos[p]) a[k].l = update(a[k].l, p ^ 1);
	else a[k].r = update(a[k].r, p ^ 1);
	return k;
}

void query(int k, int p)
{
	if (!k) return;
	//更新ans
	ans = min(ans, abs(x.pos[0] - a[k].pos[0]) + abs(x.pos[1] - a[k].pos[1]));
	int ld = a[k].l ? dis(a[k].l) : INF, rd = a[k].r ? dis(a[k].r) : INF;
	if (min(ld, rd) >= ans) return;
	if (ld < rd)
	{
		query(a[k].l, p ^ 1);
		if (rd < ans) query(a[k].r, p ^ 1);
	}
	else
	{
		query(a[k].r, p ^ 1);
		if (ld < ans) query(a[k].l, p ^ 1);
	}
}

int main()
{
	while (~scanf("%d%d", &n, &q))
	{
		for (int i = 1; i <= n; i++)
		{
			scanf("%d%d", &a[i].pos[0], &a[i].pos[1]);
			a[i].l = a[i].r = 0;
			a[i].ma[0] = a[i].mi[0] = a[i].pos[0];
			a[i].ma[1] = a[i].mi[1] = a[i].pos[1];
		}
		root = build(1, n, 0);
		while (q--)
		{
			scanf("%d%d%d", &op, &x.pos[0], &x.pos[1]);
			ans = INF;
			if (op == 2)
			{
				query(root, 0);
				printf("%d\n", ans);
			}
			else
			{
				a[++n] = x;
				a[n].l = a[n].r = 0;
				a[n].ma[0] = a[n].mi[0] = a[n].pos[0];
				a[n].ma[1] = a[n].mi[1] = a[n].pos[1];
				update(root, 0);
			}
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值