zoukankan      html  css  js  c++  java
  • 【bzoj4520】[Cqoi2016]K远点对 KD-tree+堆

    题目描述

    已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对。

    输入

    输入文件第一行为用空格隔开的两个整数 N, K。接下来 N 行,每行两个整数 X,Y,表示一个点
    的坐标。1 < =  N < =  100000, 1 < =  K < =  100, K < =  N*(N−1)/2 , 0 < =  X, Y < 2^31。

    输出

    输出文件第一行为一个整数,表示第 K 远点对的距离的平方(一定是个整数)。

    样例输入

    10 5
    0 0
    0 1
    1 0
    1 1
    2 0
    2 1
    1 2
    0 2
    3 0
    3 1

    样例输出

    9


    题解

    KD-tree+堆

    考虑求与一个点距离第k大的点怎么求:维护一个有k个元素的小根堆,表示距离,初始时都是极小值;每次扫到一个点,如果距离大于堆顶,那么就把堆顶元素换成这个距离。并根据左右子树的估价函数与堆顶的关系决定是否向下查询。最后堆顶就是答案。

    那么换成所有点之间的呢?直接维护同一个堆,对所有点求一次就好了。但是要注意,由于一对点会被计算两次,所以要维护2k个元素。

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010
    #define squ(x) (ll)(x) * (x)
    using namespace std;
    typedef long long ll;
    priority_queue<ll> q;
    int d , root;
    struct data
    {
    	int p[2] , mx[2] , mn[2] , c[2];
    	bool operator<(data a)const {return p[d] == a.p[d] ? p[d ^ 1] < a.p[d ^ 1] : p[d] < a.p[d];}
    }a[N];
    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);
    	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) : -1ll << 62) , dr = (a[k].c[1] ? getdis(a[k].c[1] , x , y) : -1ll << 62);
    	if(dn > -q.top()) q.pop() , q.push(-dn);
    	if(dl > dr)
    	{
    		if(dl > -q.top()) query(a[k].c[0] , x , y);
    		if(dr > -q.top()) query(a[k].c[1] , x , y);
    	}
    	else
    	{
    		if(dr > -q.top()) query(a[k].c[1] , x , y);
    		if(dl > -q.top()) query(a[k].c[0] , x , y);
    	}
    }
    int main()
    {
    	int n , k , i;
    	scanf("%d%d" , &n , &k);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &a[i].p[0] , &a[i].p[1]);
    	root = build(1 , n , 0);
    	for(i = 1 ; i <= 2 * k ; i ++ ) q.push(0);
    	for(i = 1 ; i <= n ; i ++ ) query(root , a[i].p[0] , a[i].p[1]);
    	printf("%lld
    " , -q.top());
    	return 0;
    }
    

     

  • 相关阅读:
    【每天半小时学框架】——React.js的模板语法与组件概念
    PHP中使用 $_GET 与$_POST 实现简单的前后台数据传输交互功能
    轻松几句搞定【Javascript中的this指向】问题
    跨平台移动端APP开发---简单高效的MUI框架
    JavaScript基本知识点整理(超实用)
    一款特好用的JavaScript框架——JQuery
    一个比较实用的商业级图表Echarts
    MUI顶部选项卡的用法(tab-top-webview-main)
    一个非常好用的前端JS框架-AngularJS(一)
    JavaScript面向对象中的继承
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7190024.html
Copyright © 2011-2022 走看看