[CQOI2016]K远点对(KD-Tree)

暴力的做法应该是这样的,维护大小为k的堆,每次插入两点间距离并弹出堆顶。

然后这个做法显然是可以KD-Tree优化的,建立KD-Tree,然后如果该平面内最远点小于堆顶,则直接退出。就当做是复习很久没做的KD-Tree了。

不过有一个细节要注意,求最远点对,(1,2)->(2,1)算一对,所以堆的大小应该是2*k

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
struct point{ll d[2];}a[N];
struct node{int mn[2],mx[2],lc,rc;point a;}t[N];
priority_queue<ll,vector<ll>,greater<ll> >q;
int n,m,rt,D;
bool operator<(point a,point b){return a.d[D]<b.d[D];}
void pushup(int x,int y)
{
    t[x].mn[0]=min(t[x].mn[0],t[y].mn[0]);
    t[x].mn[1]=min(t[x].mn[1],t[y].mn[1]);
    t[x].mx[0]=max(t[x].mx[0],t[y].mx[0]);
    t[x].mx[1]=max(t[x].mx[1],t[y].mx[1]);
}
void build(int&k,int l,int r,int d)
{
    k=0;
    if(l>r)return;
    D=d;
    int mid=l+r>>1;
    nth_element(a+l,a+mid,a+r+1);
    k=mid;
    t[k].mn[0]=t[k].mx[0]=t[k].a.d[0]=a[k].d[0];
    t[k].mn[1]=t[k].mx[1]=t[k].a.d[1]=a[k].d[1];
    build(t[k].lc,l,mid-1,d^1);
    if(t[k].lc)pushup(k,t[k].lc);
    build(t[k].rc,mid+1,r,d^1);
    if(t[k].rc)pushup(k,t[k].rc);
}
ll getdis(point a,point b)
{return(a.d[0]-b.d[0])*(a.d[0]-b.d[0])+(a.d[1]-b.d[1])*(a.d[1]-b.d[1]);}
ll getdis2(point a,node b)
{
    ll ret=0;
    ret=max(ret,getdis(a,(point){b.mn[0],b.mn[1]}));
    ret=max(ret,getdis(a,(point){b.mn[0],b.mx[1]}));
    ret=max(ret,getdis(a,(point){b.mx[0],b.mn[1]}));
    ret=max(ret,getdis(a,(point){b.mx[0],b.mx[1]}));
    return ret;
}
void query(int k,point a)
{
    ll dis=getdis(a,t[k].a);
    if(dis>q.top())q.pop(),q.push(dis);
    if(t[k].lc)
    {
        dis=getdis2(a,t[t[k].lc]);
        if(dis>q.top())query(t[k].lc,a);
    }
    if(t[k].rc)
    {
        dis=getdis2(a,t[t[k].rc]);
        if(dis>q.top())query(t[k].rc,a);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].d[0],&a[i].d[1]);
    build(rt,1,n,0);
    for(int i=1;i<=m*2;i++)q.push(0);
    for(int i=1;i<=n;i++)query(rt,a[i]);
    printf("%lld",q.top());
}

原文地址:https://www.cnblogs.com/hfctf0210/p/11179344.html

时间: 2024-11-10 13:47:10

[CQOI2016]K远点对(KD-Tree)的相关文章

【BZOJ4520】[Cqoi2016]K远点对 kd-tree+堆

[BZOJ4520][Cqoi2016]K远点对 Description 已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对. Input 输入文件第一行为用空格隔开的两个整数 N, K.接下来 N 行,每行两个整数 X,Y,表示一个点的坐标.1 < =  N < =  100000, 1 < =  K < =  100, K < =  N*(N−1)/2 , 0 < =  X, Y < 2^31. Output 输出文件第一行为一个整数,表示第 K 远点对

BZOJ 4520 [Cqoi2016]K远点对(KD树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4520 [题目大意] 求K远点对距离 [题解] 修改估价函数为欧式上界估价,对每个点进行dfs, 因为是无向点对,在小根堆中保留前2k个距离, 不断更新堆顶元素即可. [代码] #include <cstdio> #include <algorithm> #include <queue> using namespace std; typedef long lo

bzoj4520 [Cqoi2016]K远点对

Description 已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对. Input 输入文件第一行为用空格隔开的两个整数 N, K.接下来 N 行,每行两个整数 X,Y,表示一个点 的坐标.1 < =  N < =  100000, 1 < =  K < =  100, K < =  N*(N−1)/2 , 0 < =  X, Y < 2^31. Output 输出文件第一行为一个整数,表示第 K 远点对的距离的平方(一定是个整数). 将所有点建成kd

【bzoj4520】 Cqoi2016—K远点对

http://www.lydsy.com/JudgeOnline/problem.php?id=4520 (题目链接) 题意 求平面内第K远点对的距离. Solution 左转题解:jump 细节 刚开始我还开了两个堆,想想其实是没必要的→_→ 距离什么的开LL 代码 // bzoj4520 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include&

[CQOI2016]K远点对

题目 这个题好像不是那样板子了 我们考虑维护一个有\(k\)个元素的小根堆,用来存我们当前找到的前\(k\)远点对 如果是暴力的话我们就直接暴力枚举点对,计算距离往这个小根堆里插就好了,非常显然,如果距离甚至小于小根堆的堆顶,我们就没有什么插入的必要了 考虑用\(kdt\)优化这个暴力,我们枚举每一个点,让这个点在\(kdt\)上搜,一旦发现某一个子矩形和这个点形成的最大欧几里得距离多于当前堆顶,我们就不用再往下计算了 又发现这样计算一个点对会被计算两次,所以我们实际上维护一个\(2k\)的小根

LuoguP4357 [CQOI2016]K远点对

kd-tree #include<bits/stdc++.h> #define lc (ch[x][0]) #define rc (ch[x][1]) #define ll long long using namespace std; const int maxn=1e6+4; int n,m,cnt; ll mn[maxn][2],mx[maxn][2],ch[maxn][2],sz[maxn]; int nthdir; priority_queue<ll,vector<ll&g

bzoj4520【CQOI2016】K远点对

4520: [Cqoi2016]K远点对 Time Limit: 30 Sec  Memory Limit: 512 MB Submit: 497  Solved: 241 [Submit][Status][Discuss] Description 已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对. Input 输入文件第一行为用空格隔开的两个整数 N, K.接下来 N 行,每行两个整数 X,Y,表示一个点 的坐标.1 < =  N < =  100000, 1 < =  K &

【BZOJ-4520】K远点对 KD-Tree + 堆

4520: [Cqoi2016]K远点对 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 490  Solved: 237[Submit][Status][Discuss] Description 已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对. Input 输入文件第一行为用空格隔开的两个整数 N, K.接下来 N 行,每行两个整数 X,Y,表示一个点 的坐标.1 < =  N < =  100000, 1 < =  K <

KD tree

Kd-树 其实是K-dimension tree的缩写,是对数据点在k维空间中划分的一种数据结构.其实,Kd-树是一种平衡二叉树. 举一示例: 假设有六个二维数据点 = {(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},数据点位于二维空间中.为了能有效的找到最近邻,Kd-树采用分而治之的思想,即将整个空间划分为几个小部分.六个二维数据点生成的Kd-树的图为: 对于拥有n个已知点的kD-Tree,其复杂度如下: 构建:O(log2n) 插入:O(log n) 删除:O(l