1. 程式人生 > >【bzoj2626】JZPFAR KD-tree+堆

【bzoj2626】JZPFAR KD-tree+堆

左右 clu 替換 坐標 元素 util light amp nbsp

題目描述

平面上有n個點。現在有m次詢問,每次給定一個點(px, py)和一個整數k,輸出n個點中離(px, py)的距離第k大的點的標號。如果有兩個(或多個)點距離(px, py)相同,那麽認為標號較小的點距離較大。

輸入

第一行,一個整數n,表示點的個數。
下面n行,每行兩個整數x_i, y_i,表示n個點的坐標。點的標號按照輸入順序,分別為1..n。
下面一行,一個整數m,表示詢問個數。
下面m行,每行三個整數px_i, py_i, k_i,表示一個詢問。

輸出

m行,每行一個整數,表示相應的詢問的答案。

樣例輸入

3
0 0
0 1
0 2
3
1 1 2
0 0 3
0 1 1

樣例輸出

3
1
1


題解

KD-tree+堆

求與一個點距離第k大的方法:維護一個k個元素的小根堆,表示距離,初始都為極小值;然後對於每個點,如果距離比堆頂元素大,則將堆頂元素替換為該距離;並根據左右子樹的估價函數與堆頂元素的大小關系決定是否向下查詢。

然而本題中要求距離相同的編號較小者距離較大,所以我們在以距離為第一關鍵字維護小根堆的同時以編號第二關鍵字維護大根堆即可。

註意在估價與堆頂相等時也要向下查詢,因為可能存在編號的問題。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <algorithm>
#define squ(x) (ll)(x) * (x)
#define N 100010
using namespace std;
typedef long long ll;
priority_queue<pair<ll , int> > q;
struct data
{
	int p[2] , mx[2] , mn[2] , id , c[2];
}a[N];
int d , root , num;
bool cmp(data a , data b)
{
	return a.p[d] == b.p[d] ? a.p[d ^ 1] < b.p[d ^ 1] : a.p[d] < b.p[d];
}
void pushup(int k , int x)
{
	a[k].mx[0] = max(a[k].mx[0] , a[x].mx[0]);
	a[k].mn[0] = min(a[k].mn[0] , a[x].mn[0]);
	a[k].mx[1] = max(a[k].mx[1] , a[x].mx[1]);
	a[k].mn[1] = min(a[k].mn[1] , a[x].mn[1]);
}
int build(int l , int r , int now)
{
	int mid = (l + r) >> 1;
	d = now , nth_element(a + l , a + mid , a + r + 1 , cmp);
	a[mid].mx[0] = a[mid].mn[0] = a[mid].p[0];
	a[mid].mx[1] = a[mid].mn[1] = a[mid].p[1];
	if(l < mid) a[mid].c[0] = build(l , mid - 1 , now ^ 1) , pushup(mid , a[mid].c[0]);
	if(r > mid) a[mid].c[1] = build(mid + 1 , r , now ^ 1) , pushup(mid , a[mid].c[1]);
	return mid;
}
ll getdis(int k , int x , int y)
{
	return max(squ(a[k].mx[0] - x) , squ(a[k].mn[0] - x)) + max(squ(a[k].mx[1] - y) , squ(a[k].mn[1] - y));
}
void query(int k , int x , int y)
{
	ll dn = squ(a[k].p[0] - x) + squ(a[k].p[1] - y) , dl = (a[k].c[0] ? getdis(a[k].c[0] , x , y) : -1) , dr = (a[k].c[1] ? getdis(a[k].c[1] , x , y) : -1);
	if(make_pair(-dn , a[k].id) < q.top())
		q.pop() , q.push(make_pair(-dn , a[k].id));
	if(dl > dr)
	{
		if(dl >= -q.top().first) query(a[k].c[0] , x , y);
		if(dr >= -q.top().first) query(a[k].c[1] , x , y);
	}
	else
	{
		if(dr >= -q.top().first) query(a[k].c[1] , x , y);
		if(dl >= -q.top().first) query(a[k].c[0] , x , y);
	}
}
int main()
{
	int n , i , m , x , y , k;
	scanf("%d" , &n);
	for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &a[i].p[0] , &a[i].p[1]) , a[i].id = i;
	root = build(1 , n , 0);
	scanf("%d" , &m);
	while(m -- )
	{
		scanf("%d%d%d" , &x , &y , &k);
		while(!q.empty()) q.pop();
		for(i = 1 ; i <= k ; i ++ ) q.push(make_pair(0 , 1 << 30));
		query(root , x , y);
		printf("%d\n" , q.top().second);
	}
	return 0;
}

【bzoj2626】JZPFAR KD-tree+堆