2648: SJY摆棋子

2648: SJY摆棋子

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 2739   Solved: 939
[ 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]




HINT既然说了kdtree那就kdtree吧。。

建树的话,,上篇blog转载了一位大牛的做法,这里就不说了

不过苟蒻之前对kdtree的功能还不是很熟


插入操作:

kdtree建好后每次沿着当前比较关键字(x坐标或y坐标)往下走,走到空位就插进去

查询操作:

对于每个位置维护当前坐标的极大/小值,如果某一维需要查询的坐标在这之间,这一维贡献为0,否则就可以计算出贡献,用这种方法预估dis


对于nth_element函数:

nth_element(a+l,a+mid,a+r)能在O(n)时间内对区间[l,r)内的元素进行一次粗略排序,使得第mid个元素恰好在mid位置上


此题还有数据加强板2716,双倍经验~

#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 1E6 + 3E5 + 10;
const int INF = ~0U>>1;

struct Point{
	int x,y;
	Point(){}
	Point(int x,int y): x(x),y(y){}
}p[maxn];

int n,m,cnt,ans,td[2],D[maxn][2],ma[maxn][2],mi[maxn][2],ch[maxn][2];

void maintain(int x)
{
	for (int i = 0; i < 2; i++)
		if (ch[x][i]) 
			for (int j = 0; j < 2; j++) {
				ma[x][j] = max(ma[x][j],ma[ch[x][i]][j]);
				mi[x][j] = min(mi[x][j],mi[ch[x][i]][j]);
			}
}

bool cmp0(const Point &a,const Point &b) {return a.x < b.x;}
bool cmp1(const Point &a,const Point &b) {return a.y < b.y;}

int Build(int l,int r,int k)
{
	int mid = (l + r) >> 1;
	if (!k) nth_element(p + l,p + mid,p + r + 1,cmp0);
	else nth_element(p + l,p + mid,p + r + 1,cmp1);
	int ret = ++cnt;
	D[cnt][0] = ma[cnt][0] = mi[cnt][0] = p[mid].x;
	D[cnt][1] = ma[cnt][1] = mi[cnt][1] = p[mid].y;
	if (l < mid) ch[ret][0] = Build(l,mid-1,k^1);
	if (mid < r) ch[ret][1] = Build(mid+1,r,k^1);
	maintain(ret);
	return ret;
}

void Insert(int &x,int k)
{
	if (!x) {
		x = ++cnt;
		for (int i = 0; i < 2; i++)
			D[x][i] = ma[x][i] = mi[x][i] = td[i];
		return;
	}
	if (D[x][0] == td[0] && D[x][1] == td[1]) return;
	int d = td[k] <= D[x][k]?0:1;
	Insert(ch[x][d],k^1);
	maintain(x);
}

int dis(int x)
{
	if (!x) return INF;
	int ret = 0;
	if (td[0] < mi[x][0]) ret += mi[x][0] - td[0];
	if (ma[x][0] < td[0]) ret += td[0] - ma[x][0];
	if (td[1] < mi[x][1]) ret += mi[x][1] - td[1];
	if (ma[x][1] < td[1]) ret += td[1] - ma[x][1];
	return ret;
}

void Query(int x)
{
	int now = abs(td[0] - D[x][0]) + abs(td[1] - D[x][1]);
	ans = min(ans,now);
	int A = dis(ch[x][0]);
	int B = dis(ch[x][1]);
	if (A < B) {
		if (ch[x][0] && A < ans) Query(ch[x][0]);
		if (ch[x][1] && B < ans) Query(ch[x][1]);
	}
	else {
		if (ch[x][1] && B < ans) Query(ch[x][1]);
		if (ch[x][0] && A < ans) Query(ch[x][0]);
	}
}

int getint()
{
	char ch = getchar();
	int ret = 0,a = 1;
	while (ch < '0' || '9' < ch) {
		if (ch == '-') a = -1;
		ch = getchar();
	}
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret*a;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	n = getint();
	m = getint();
	for (int i = 1; i <= n; i++) {
		int x = getint();
		int y = getint();
		p[i] = Point(x,y);
	}
	int Root = Build(1,n,0);
	while (m--) {
		int t = getint();
		td[0] = getint();
		td[1] = getint();
		if (t == 1) Insert(Root,0);
		else {
			ans = INF;
			Query(Root);
			printf("%d\n",ans);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值