那你看到它要所有两对点,那你就把每两个点之间的距离都放进去比较。
然后你就想到先把每个点丢进 K-D tree 里面,然后再用所有的点轮流去查询,然后把所有的距离用堆维护出前 k 大。
然后你会发现 a 到 b 和 b 到 a 你是比较了两次的,但它其实只算一次。
(你 a 会查询到 b,b 会查询到 a)
那也就是说,两个点之间的距离会被放进去两次,那你很容易想到,你就直接搞一个 2k 的堆,然后最后的堆顶就是我们的第 k 大了。
代码
#include<queue>#include<cstdio>#include<algorithm>#define ll long long#define INF 10000000usingnamespace std;
structzb {
int w[2];
}a[200001];
structKDtree {
int l, r, ma[2], mi[2];
}tree[200001];
int n, k, root, WD, num[200001];
priority_queue <ll, vector<ll>, greater<ll> > q;
boolcmp(int x, int y){
return a[x].w[WD] < a[y].w[WD];
}
voidup(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]);
}
}
}
intbuild(int l, int r, int wd){
if (l > r) return0;
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;
}
voidquery(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);
}
}
intmain(){
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());
return0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现