【ybt金牌导航4-2-3】【luogu P4357】K远点对

K远点对

题目链接:ybt金牌导航4-2-3 / luogu P4357

题目大意

一个平面上有一些点,你要找到第 K 远对点之间的距离。
距离是用勾股的那个算。

思路

那你看到平面距离自然想到 K-D tree。

那你看到它要所有两对点,那你就把每两个点之间的距离都放进去比较。
然后你就想到先把每个点丢进 K-D tree 里面,然后再用所有的点轮流去查询,然后把所有的距离用堆维护出前 k 大。
然后你会发现 abba 你是比较了两次的,但它其实只算一次。
(你 a 会查询到 bb 会查询到 a

那也就是说,两个点之间的距离会被放进去两次,那你很容易想到,你就直接搞一个 2k 的堆,然后最后的堆顶就是我们的第 k 大了。

代码

#include<queue> #include<cstdio> #include<algorithm> #define ll long long #define INF 10000000 using namespace std; struct zb { int w[2]; }a[200001]; struct KDtree { int l, r, ma[2], mi[2]; }tree[200001]; int n, k, root, WD, num[200001]; priority_queue <ll, vector<ll>, greater<ll> > q; bool cmp(int x, int y) { return a[x].w[WD] < a[y].w[WD]; } void up(int now) { for (int i = 0; i < 2; i++) { tree[now].ma[i] = tree[now].mi[i] = a[now].w[i]; if (tree[now].l) { tree[now].ma[i] = max(tree[now].ma[i], tree[tree[now].l].ma[i]); tree[now].mi[i] = min(tree[now].mi[i], tree[tree[now].l].mi[i]); } if (tree[now].r) { tree[now].ma[i] = max(tree[now].ma[i], tree[tree[now].r].ma[i]); tree[now].mi[i] = min(tree[now].mi[i], tree[tree[now].r].mi[i]); } } } int build(int l, int r, int wd) { if (l > r) return 0; int mid = (l + r) >> 1; WD = wd; nth_element(num + l, num + mid, num + r + 1, cmp); int now = num[mid]; tree[now].l = build(l, mid - 1, wd ^ 1); tree[now].r = build(mid + 1, r, wd ^ 1); up(now); return now; } ll get_dis(zb x, zb y) { ll X = x.w[0] - y.w[0]; ll Y = x.w[1] - y.w[1]; return X * X + Y * Y; } ll abss(ll x) { if (x < 0) return -x; return x; } ll blog_dis(zb x, KDtree y) { ll X = max(abss(x.w[0] - y.ma[0]), abss(x.w[0] - y.mi[0])); ll Y = max(abss(x.w[1] - y.ma[1]), abss(x.w[1] - y.mi[1])); return X * X + Y * Y; } void query(zb now, int root) { if (!root) return ; ll diss = get_dis(now, a[root]); if (diss > q.top()) { q.pop(); q.push(diss); } ll ldis = -INF; ll rdis = -INF; if (tree[root].l) ldis = blog_dis(now, tree[tree[root].l]); if (tree[root].r) rdis = blog_dis(now, tree[tree[root].r]); if (ldis > rdis) { if (ldis > q.top()) query(now, tree[root].l); if (rdis > q.top()) query(now, tree[root].r); } else { if (rdis > q.top()) query(now, tree[root].r); if (ldis > q.top()) query(now, tree[root].l); } } int main() { scanf("%d %d", &n, &k); for (int i = 1; i <= n; i++) { scanf("%d %d", &a[i].w[0], &a[i].w[1]); num[i] = i; } root = build(1, n, 0); k <<= 1;//由于 a 到 b 和 b 到 a 两个是一样的但算了两次,所以我们索性就求出你这些所有距离的第 2k 大 for (int i = 1; i <= k; i++) q.push(-1); for (int i = 1; i <= n; i++) {//把每个点和其他点之间的距离都比较一次,维护前 2k 大 query(a[i], root); } printf("%lld", q.top()); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_4-2-3.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(28)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示