P4357 [CQOI2016]K 远点对

题目链接

P4357 [CQOI2016]K 远点对

题目描述

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

两个点 P(x1,y1)Q(x2,y2) 的欧氏距离定义为 (x1x2)2+(y1y2)2

输入格式

输入文件第一行为用空格隔开的两个整数 N,K

接下来 N 行,每行两个整数 X,Y ,表示一个点的坐标。

输出格式

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

样例 #1

样例输入 #1

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

样例输出 #1

9

提示

对于 100% 的测试点,N100000,1K100,KN(N1)2,0X,Y<231

解题思路

kdtree

P7883 平面最近点对(加强加强版),枚举点时,只需在 kdtree 上维护点到矩形的最远距离,同时用小根堆维护前 2k 大的点(由于求得点对会重复计算),最后小根堆栈顶元素即为答案

  • 时间复杂度:O(n×n)

代码

// Problem: P4357 [CQOI2016]K 远点对 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P4357 // Memory Limit: 500 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> // #define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1e5+5; int n,k; priority_queue<LL,vector<LL>,greater<LL>> q; struct Point { int x,y; }point[N]; struct Tr { int s[2]; int U,D,L,R; }tr[N]; bool cmp1(const Point &x,const Point &y) { return x.x<y.x; } bool cmp2(const Point &x,const Point &y) { return x.y<y.y; } void pushup(int x) { tr[x].L=tr[x].R=point[x].x; tr[x].U=tr[x].D=point[x].y; if(tr[x].s[0]) { tr[x].L=min(tr[x].L,tr[tr[x].s[0]].L); tr[x].D=min(tr[x].D,tr[tr[x].s[0]].D); tr[x].R=max(tr[x].R,tr[tr[x].s[0]].R); tr[x].U=max(tr[x].U,tr[tr[x].s[0]].U); } if(tr[x].s[1]) { tr[x].L=min(tr[x].L,tr[tr[x].s[1]].L); tr[x].D=min(tr[x].D,tr[tr[x].s[1]].D); tr[x].R=max(tr[x].R,tr[tr[x].s[1]].R); tr[x].U=max(tr[x].U,tr[tr[x].s[1]].U); } } int build(int l,int r) { if(l>r)return 0; if(l==r) { pushup(l); return l; } int mid=l+r>>1; double avg[2]={0},va[2]={0}; for(int i=l;i<=r;i++)avg[0]+=point[i].x,avg[1]+=point[i].y; avg[0]/=(double)(r-l+1),avg[1]/=(double)(r-l+1); for(int i=l;i<=r;i++) { va[0]+=(point[i].x-avg[0])*(point[i].x-avg[0]); va[1]+=(point[i].y-avg[1])*(point[i].y-avg[1]); } if(va[0]>=va[1])nth_element(point+l,point+mid,point+r+1,cmp1); else nth_element(point+l,point+mid,point+r+1,cmp2); tr[mid].s[0]=build(l,mid-1),tr[mid].s[1]=build(mid+1,r); pushup(mid); return mid; } LL dist(Point x,Point y) { return (LL)(x.x-y.x)*(x.x-y.x)+(LL)(x.y-y.y)*(x.y-y.y); } LL get(int x,int y) { int dx=max(abs(point[y].x-tr[x].L),abs(point[y].x-tr[x].R)); int dy=max(abs(point[y].y-tr[x].U),abs(point[y].y-tr[x].D)); return (LL)dx*dx+(LL)dy*dy; } void ask(int l,int r,int x) { if(l>r)return ; int mid=l+r>>1; if(x!=mid) q.push(dist(point[x],point[mid])); if(q.size()>k)q.pop(); LL distL=get(tr[mid].s[0],x),distR=get(tr[mid].s[1],x); if(distL>q.top()&&distR>q.top()) { if(distL>distR) { ask(l,mid-1,x); if(q.size()<k||distR>q.top())ask(mid+1,r,x); } else { ask(mid+1,r,x); if(q.size()<k||distL>q.top())ask(l,mid-1,x); } } else { if(q.size()<k||distL>q.top())ask(l,mid-1,x); if(q.size()<k||distR>q.top())ask(mid+1,r,x); } } int main() { scanf("%d%d",&n,&k); k<<=1; for(int i=1;i<=n;i++)scanf("%d%d",&point[i].x,&point[i].y); build(1,n); for(int i=1;i<=n;i++)ask(1,n,i); printf("%lld",q.top()); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16828874.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2021-10-26 拓扑排序
点击右上角即可分享
微信分享提示