版权声明:欢迎转载蒟蒻博客,但请注明出处:blog.csdn.net/lpa20020220 https://blog.csdn.net/LPA20020220/article/details/82391918
洛谷传送门
BZOJ传送门
题目描述
平面上有 个点。现在有 次询问,每次给定一个点 和一个整数 ,输出 个点中离 的距离第 大的点的标号。如果有两个(或多个)点距离 相同,那么认为标号较小的点距离较大。
输入输出格式
输入格式:
第一行,一个整数 ,表示点的个数。
下面 行,每行两个整数 , ,表示 个点的坐标。点的标号按照输入顺序,分别为 。
下面一行,一个整数 ,表示询问个数。
下面 行,每行三个整数 ,表示一个询问。
输出格式:
行,每行一个整数,表示相应的询问的答案。
输入输出样例
输入样例#1:
3
0 0
0 1
0 2
3
1 1 2
0 0 3
0 1 1
输出样例#1:
3
1
1
说明
50%的数据中, 个点的坐标在某范围内随机分布。
100%的数据中, ,所有点(包括询问的点)的坐标满足绝对值 , 个点中任意两点坐标不同, 个询问的点的坐标在某范围内随机分布。
解题分析
很明显还是用 解决。 为了找到前 远, 我们维护一个大小为 的小根堆, 预先 进 个 。 然后递归查询的时候如果当前区间最大值可能比堆顶大那么就递归进入尝试更新。
复杂度? 常数大的要死……
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <cstdlib>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100050
#define ll long long
bool neg;
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc)
if(c == '-') neg = true;
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
if(neg) neg = false, x = -x;
}
int dot, q, dim, root, k;
ll x, y;
struct INFO {int id; ll dis;};
IN bool operator < (const INFO &x, const INFO &y)
{return x.dis == y.dis ? x.id < y.id : x.dis > y.dis;}
std::priority_queue <INFO> pq;
struct Node {ll lim[2][2], cood[2]; int son[2], id;} tree[MX];
IN bool operator < (const Node &x, const Node &y)
{return x.cood[dim] == y.cood[dim] ? x.cood[dim ^ 1] < y.cood[dim ^ 1] : x.cood[dim] < y.cood[dim];}
namespace KDT
{
using std::min; using std::max;
#define ls tree[now].son[0]
#define rs tree[now].son[1]
IN void pushup(R int now)
{
tree[now].lim[0][0] = tree[now].lim[0][1] = tree[now].cood[0];
tree[now].lim[1][0] = tree[now].lim[1][1] = tree[now].cood[1];
if(ls)
{
tree[now].lim[0][0] = min(tree[now].lim[0][0], tree[ls].lim[0][0]);
tree[now].lim[0][1] = max(tree[now].lim[0][1], tree[ls].lim[0][1]);
tree[now].lim[1][0] = min(tree[now].lim[1][0], tree[ls].lim[1][0]);
tree[now].lim[1][1] = max(tree[now].lim[1][1], tree[ls].lim[1][1]);
}
if(rs)
{
tree[now].lim[0][0] = min(tree[now].lim[0][0], tree[rs].lim[0][0]);
tree[now].lim[0][1] = max(tree[now].lim[0][1], tree[rs].lim[0][1]);
tree[now].lim[1][0] = min(tree[now].lim[1][0], tree[rs].lim[1][0]);
tree[now].lim[1][1] = max(tree[now].lim[1][1], tree[rs].lim[1][1]);
}
}
int build(R int lef, R int rig, R int d)
{
dim = d; R int mid = lef + rig >> 1, now = mid;
std::nth_element(tree + lef, tree + mid, tree + rig + 1);
if(lef < mid) ls = build(lef, mid - 1, d ^ 1);
if(rig > mid) rs = build(mid + 1, rig, d ^ 1);
pushup(now); return now;
}
IN ll getdis(ll bx, ll by) {return (x - bx) * (x - bx) + (y - by) * (y - by);}
IN ll sqr(ll x) {return x * x;}
IN ll mxdis(R int id) {return max(sqr(x - tree[id].lim[0][0]), sqr(x - tree[id].lim[0][1])) + max(sqr(y - tree[id].lim[1][0]), sqr(y - tree[id].lim[1][1]));}
IN void query(R int now)
{
ll dl = -1, dr = -1, dnow;
dnow = getdis(tree[now].cood[0], tree[now].cood[1]);
if(ls) dl = mxdis(ls);
if(rs) dr = mxdis(rs);
if((INFO){tree[now].id, dnow} < pq.top()) pq.pop(), pq.push({tree[now].id, dnow});
if(dl > dr)
{
if((INFO){-1, dl} < pq.top()) query(ls);
if((INFO){-1, dr} < pq.top()) query(rs);
}
else
{
if((INFO){-1, dr} < pq.top()) query(rs);
if((INFO){-1, dl} < pq.top()) query(ls);
}
}
#undef ls
#undef rs
}
int main(void)
{
in(dot);
for (R int i = 1; i <= dot; ++i) in(tree[i].cood[0]), in(tree[i].cood[1]), tree[i].id = i;
root = KDT::build(1, dot, 0);
in(q);
W (q--)
{
in(x), in(y), in(k);
W (!pq.empty()) pq.pop();
W (k--) pq.push({-1, -1});
KDT::query(root);
printf("%d\n", pq.top().id);
}
}