嘟嘟嘟




k-d tree模板之二:查询第k大距离。(所以是怎么上黑的)




因为k-d tree的查询就是暴力嘛,所以我就想到了一个很暴力的做法:每一次查询用一个长度为k的优先队列维护。按距离递增,编号递减的方式排序。

然后查询的时候,如果队列长度大于k了,就尝试用当前节点更新队首。

刚开始没看到k的范围只有20,以为也是1e5,所以觉得这方法不行,最后还是看了题解……

结果题解做法和我几乎一样,只不过有点优化:

1.先往队列里放入k个极小值,就能避免队空以及判断长度等问题。

2.查询的时候优先往估价函数大的子树查询,这样这个子树查完后可能就不会进入估价函数小的兄弟了。

3.对了,这里的估价函数是最长距离。

然后我自认为我的查询代码比题解简单:固定往左子树找,如果左子树估价函数小于右子树,就交换左右子树。这样是没有影响的,还避免了复杂的分类讨论。




k-d tree debug也特别简单,直接改成爆搜,就知道是建树错了还是查询错了。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 1e5 + 5;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
} int n, m, Dim;
struct Tree
{
int ch[2], id;
ll d[2], Min[2], Max[2];
In bool operator < (const Tree& oth)const
{
return d[Dim] < oth.d[Dim];
}
}t[maxn << 2], a[maxn];
int root, tcnt = 0;
In void pushup(int now)
{
for(int i = 0; i < 2; ++i)
{
if(t[now].ch[0])
{
t[now].Min[i] = min(t[now].Min[i], t[t[now].ch[0]].Min[i]);
t[now].Max[i] = max(t[now].Max[i], t[t[now].ch[0]].Max[i]);
}
if(t[now].ch[1])
{
t[now].Min[i] = min(t[now].Min[i], t[t[now].ch[1]].Min[i]);
t[now].Max[i] = max(t[now].Max[i], t[t[now].ch[1]].Max[i]);
}
}
}
In void build(int& now, int L, int R, int d)
{
if(L > R) return;
int mid = (L + R) >> 1;
Dim = d;
nth_element(a + L, a + mid, a + R + 1);
t[now = ++tcnt] = a[mid];
for(int i = 0; i < 2; ++i)
{
t[now].ch[i] = 0;
t[now].Min[i] = t[now].Max[i] = t[now].d[i];
}
build(t[now].ch[0], L, mid - 1, d ^ 1);
build(t[now].ch[1], mid + 1, R, d ^ 1);
pushup(now);
} struct Node
{
ll dis; int id;
In bool operator < (const Node& oth)const
{
return dis > oth.dis || (dis == oth.dis && id < oth.id);
}
};
priority_queue<Node> q;
In ll dis(int now, ll* d)
{
ll ret = 0;
for(int i = 0; i < 2; ++i) ret += (t[now].d[i] - d[i]) * (t[now].d[i] - d[i]);
return ret;
}
In ll price(int now, ll* d)
{
ll ret = 0;
for(int i = 0; i < 2; ++i)
{
ll Max = max(abs(t[now].Max[i] - d[i]), abs(t[now].Min[i] - d[i]));
ret += Max * Max;
}
return ret;
}
In void query(int now, ll* d)
{
if(!now) return;
ll tp = dis(now, d);
if(tp > q.top().dis || (tp == q.top().dis && t[now].id < q.top().id)) q.pop(), q.push((Node){tp, t[now].id});
ll disL = price(t[now].ch[0], d), disR = price(t[now].ch[1], d);
if(disL < disR) swap(t[now].ch[0], t[now].ch[1]), swap(disL, disR);
if(disL > q.top().dis || (disL == q.top().dis && t[t[now].ch[0]].id < q.top().id)) query(t[now].ch[0], d);
if(disR > q.top().dis || (disR == q.top().dis && t[t[now].ch[1]].id < q.top().id)) query(t[now].ch[1], d);
} int main()
{
n = read();
for(int i = 1; i <= n; ++i) a[i].d[0] = read(), a[i].d[1] = read(), a[i].id = i;
build(root, 1, n, 0);
m = read();
for(int i = 1; i <= m; ++i)
{
static ll d[2];
d[0] = read(), d[1] = read(); int k = read();
while(!q.empty()) q.pop();
for(int j = 1; j <= k; ++j) q.push((Node){-1, 0});
query(root, d);
write(q.top().id), enter;
}
return 0;
}

[国家集训队]JZPFAR的更多相关文章

  1. p2093 [国家集训队]JZPFAR

    传送门 分析 首先给大家推荐一个非常好的KDTree笔记 here 此题就是y9ong优先队列维护距离最远的k个,最后输出队首元素即可 估价函数就是max和min两点到 询问点的最远距离 代码 #in ...

  2. luogu2093 [国家集训队]JZPFAR

    题面不符?-- #include <algorithm> #include <iostream> #include <cstdio> using namespace ...

  3. P2093 [国家集训队]JZPFAR(KDTree)

    传送门 类似于p4357 不过因为距离相等的时候要优先选择序号小的,所以要重载一下运算符 //minamoto #include<bits/stdc++.h> #define R regi ...

  4. luogu P2093 [国家集训队]JZPFAR

    传送门 要维护平面上点的信息,所以可以用KD-tree来维护,然后维护一个大小为\(k\)的堆,每次从根开始遍历,遇到一个点就看能不能作为前\(k\)远的点,也就是看能不能把堆中最近的点给替换掉.如果 ...

  5. [国家集训队2012]JZPFAR

    [国家集训队2012]JZPFAR 题目 平面上有n个点.现在有m次询问,每次给定一个点(px, py)和一个整数k,输出n个点中离(px, py)的距离第k大的点的标号.如果有两个(或多个)点距离( ...

  6. BZOJ 2039: [2009国家集训队]employ人员雇佣

    2039: [2009国家集训队]employ人员雇佣 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1369  Solved: 667[Submit ...

  7. BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7687  Solved: 3516[Subm ...

  8. BZOJ 2038: [2009国家集训队]小Z的袜子(hose)

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7676  Solved: 3509[Subm ...

  9. [转] ACM中国国家集训队论文集目录(1999-2009)

    国家集训队1999论文集 陈宏:<数据结构的选择与算法效率——从IOI98试题PICTURE谈起>来煜坤:<把握本质,灵活运用——动态规划的深入探讨>齐鑫:<搜索方法中的 ...

随机推荐

  1. 教你控制 RecyclerView 滑动的节奏

    最近,PM升级改版落地页,其中有一个很奇怪的交互需求,需求是这样的: 用户在该页面可以上下无限滑动,但是,在上拉滑动过程中,当内容切换为另一个内容的时候,新的内容先吸顶,然后停止滑动,让用户知道他已经 ...

  2. Fibonacci快速实现(优化)

    斐波那契数列的通俗解法是利用递推公式进行递归求解,我们可以更优化的去解决它. 方法一:通项公式 斐波那契数列的递推公式是f(n)=f(n-1)+f(n-2),特征方程为:x2=x+1,解该方程得(1+ ...

  3. IdentityServer4 中文文档 -6- (简介)示例服务器和测试

    IdentityServer4 中文文档 -6- (简介)示例服务器和测试 原文:http://docs.identityserver.io/en/release/intro/test.html 目 ...

  4. vue 前台传后台

    var the = this:let url = "/api/Purchase_Enter/CancelEnter"; let params = { Enter_Id: Enter ...

  5. c# 判断是否是手机访问

    public static bool CheckAgent() { bool flag = false; string agent = HttpContext.Current.Request.User ...

  6. java根据年月显示每周

    一.页面效果 1.展示7月份的所有周. 2.当前时间2018.08.02  ,  显示到本周. 二.前端代码 1.显示层的代码 <span id="weekyear"> ...

  7. 【Tomcat】性能优化

    一.JVM优化 1.内存优化. 2.垃圾回收策略优化. 二.server.xml的connector优化(connector是与HTTP请求处理相关的容器,三个容器的初始化顺序为:Server-> ...

  8. UserControl VS TemplatedControl

    一:首先来看一下UserControl 熟悉XAML的朋友们都知道,当我们创建一个用户控件的时候,VS会自动为我们生成一个XXX.xaml文件和XXX..xaml.cs文件,XAML文件用于进行控件的 ...

  9. React Render Props 模式

    概述 Render Props模式是一种非常灵活复用性非常高的模式,它可以把特定行为或功能封装成一个组件,提供给其他组件使用让其他组件拥有这样的能力,接下来我们一步一步来看React组件中如何实现这样 ...

  10. php+smarty轻松开发微社区/微论坛

    今天我们就来分析微社区的基本功能构成吧.首先,每个论坛最主要的是会员在对应的版块下发帖,或者在感兴趣的主题帖下跟帖盖楼.其次,会员能时时看到帖子或版块的基本信息.所以主要大块是: 前台:会员的注册登录 ...