BZOJ 2626 JZPFAR K-D树

题目大意:给出平面上的一些点,求到一个点的最远的第k个点的标号。

思路:朴素的K-D树建树,然后在搜索的时候维护一个小跟堆,保留着最大的k个点,然后吧第k大的点作为基准点来判断是否更新其他的点。

CODE:

#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
#define INF 0x3f3f3f3f
using namespace std;

int dim;

struct Point{
	long long x,y;
	int id;

	Point(long long _ = 0,long long __ = 0):x(_),y(__) {}
	bool operator <(const Point &a)const {
		if(dim)	return x < a.x;
		return y < a.y;
	}
	void Read(int p) {
		scanf("%lld%lld",&x,&y);
		id = p;
	}
}point[MAX];

inline long long Calc(const Point &p1,const Point &p2)
{
	return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}

struct KDTree{
	KDTree *son[2];
	Point root;
	long long x0,y0,x1,y1;

	KDTree(KDTree *_,KDTree *__,Point ___) {
		son[0] = _,son[1] = __;
		root = ___;
		x0 = x1 = ___.x;
		y0 = y1 = ___.y;
	}
	KDTree() {}
	void Maintain(KDTree *a) {
		x0 = min(x0,a->x0);
		x1 = max(x1,a->x1);
		y0 = min(y0,a->y0);
		y1 = max(y1,a->y1);
	}
	long long Dis(const Point &p) {
		long long re = 0;
		re = max(re,Calc(p,Point(x0,y0)));
		re = max(re,Calc(p,Point(x1,y0)));
		re = max(re,Calc(p,Point(x1,y1)));
		re = max(re,Calc(p,Point(x0,y1)));
		return re;
	}
}*root,none,*nil = &none;

struct Complex{
	long long dis;
	int id;

	Complex(long long _,int __):dis(_),id(__) {}
	bool operator <(const Complex &a)const {
		if(dis == a.dis)	return id < a.id;
		return dis > a.dis;
	}
};

int cnt,asks;

KDTree *BuildTree(int l,int r,int d)
{
	if(l > r)	return nil;
	dim = d;
	int mid = (l + r) >> 1;
	nth_element(point + l,point + mid,point + r + 1);
	KDTree *re = new KDTree(BuildTree(l,mid - 1,!d),BuildTree(mid + 1,r,!d),point[mid]);
	if(re->son[0] != nil)	re->Maintain(re->son[0]);
	if(re->son[1] != nil)	re->Maintain(re->son[1]);
	return re;
}

priority_queue<Complex> q;

void Ask(KDTree *a,const Point &p)
{
	long long dis = Calc(p,a->root);
	Complex temp(dis,a->root.id);
	if(temp < q.top()) {
		q.push(temp);
		q.pop();
	}
	long long l = a->son[0] == nil ? -1:a->son[0]->Dis(p);
	long long r = a->son[1] == nil ? -1:a->son[1]->Dis(p);
	if(l > r) {
		if(a->son[0] != nil)
			Ask(a->son[0],p);
		if(a->son[1] != nil && r >= q.top().dis)
			Ask(a->son[1],p);
	}
	else {
		if(a->son[1] != nil)
			Ask(a->son[1],p);
		if(a->son[0] != nil && l >= q.top().dis)
			Ask(a->son[0],p);
	}
}

int main()
{
	cin >> cnt;
	for(int i = 1; i <= cnt; ++i)
		point[i].Read(i);
	root = BuildTree(1,cnt,0);
	cin >> asks;
	for(int k,i = 1; i <= asks; ++i) {
		Point p;
		p.Read(0);
		scanf("%d",&k);
		while(!q.empty())	q.pop();
		for(int i = 1; i <= k; ++i)	q.push(Complex(-INF,0));
		Ask(root,p);
		printf("%d\n",q.top().id);
	}
	return 0;
}

时间: 2024-07-31 15:55:42

BZOJ 2626 JZPFAR K-D树的相关文章

BZOJ 2626: JZPFAR

Description 求平面第\(k\)远的点,\(n\leqslant 10^5\) Solution KD-Tree. 用一个堆统计答案即可... Code /************************************************************** Problem: 2626 User: BeiYu Language: C++ Result: Accepted Time:16080 ms Memory:4824 kb ******************

BZOJ 2626 JZPFAR(KD-tree)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2626 题意:平面上有n个点.现在有m次询问,每次给定一个点(px, py)和一个整数k,输出n个点中离(px, py)的距离第k大的点的标号.如果有两个(或多个)点距离(px, py)相同,那么认为标号较小的点距离较大. 思路:对n个点做KDtree. 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath

树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Outpu

bzoj 2120: 数颜色 线段树套平衡树

/************************************************************** Problem: 2120 User: wangyucheng Language: C++ Result: Time_Limit_Exceed ****************************************************************/ #include<iostream> #include<cstdio> #incl

Bzoj 2752 高速公路 (期望,线段树)

Bzoj 2752 高速公路 (期望,线段树) 题目链接 这道题显然求边,因为题目是一条链,所以直接采用把边编上号.看成序列即可 \(1\)与\(2\)号点的边连得是. 编号为\(1\)的点.查询的时候把\(r - 1\)就好了. 这里的期望显然就是路径的平均值. 期望值: \[\dfrac{\sum_{i=l}^r\sum_{j=l}^{r}dis[i][j]}{C_{r-l+1}^2}\] 下面部分可以直接算出: 上面这一部分比较难维护. 考虑每一条边会被走过多少次. \[ans = \su

BZOJ 1502:月下柠檬树

BZOJ 1502:月下柠檬树 题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1502 题目大意:给出一棵有圆台构成的树以及一个平行光源,问树的阴影面积. 计算几何 Simpson积分 第一次写计算几何题,一直wa...明天补

BZOJ 1089 严格n元树 (递推+高精度)

题解:用a[i]表<=i时有几种树满足度数要求,那么这样就可以递归了,a[i]=a[i-1]^n+1.n个节点每个有a[i-1]种情况,那么将其相乘,最后加上1,因为深度为0也算一种.那么答案就是a[n]-a[n-1].然后就是高精度的问题了,发现很久没有现码高精度没手感了,连高进度加法进位都出了些问题,需要特别注意. #include <cstdio> #include <cstring> #include <algorithm> using namespace

[BZOJ 3110] [Zjoi2013] K大数查询 【树套树】

题目链接: BZOJ - 3110 题目分析 这道题是一道树套树的典型题目,我们使用线段树套线段树,一层是区间线段树,一层是权值线段树.一般的思路是外层用区间线段树,内层用权值线段树,但是这样貌似会很难写.多数题解都使用了外层权值线段树,内层区间线段树,于是我就这样写了.每次插入会在 logn 棵线段树中一共建 log^2(n) 个结点,所以空间应该开到 O(nlog^2(n)) .由于这道题查询的是区间第 k 大,所以我们存在线段树中的数值是输入数值的相反数(再加上 n 使其为正数),这样查第

BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )

BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ----------------------------------------------------------------------------------------- #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std;