【题解】P9062
考虑套用平面最近点对的网格化做法。在平面最近点对中,每次选取当前答案
考虑拓展上述做法,实际上只需要关心
于是枚举
对于每一块,只需要按编号排序,然后取相邻的计算贡献即可覆盖全部。对于相邻的两块,将两块的点同时按编号排序,可以发现有贡献的点对在排序后的序列上距离
此时问题转化为
实现时取相邻的
代码:
#include <bits/stdc++.h>
int read (void)
{
int x = 0; char ch = getchar();
while (ch < '0' or ch > '9') ch = getchar();
while (ch >= '0' and ch <= '9') x = x * 10 + ch - 48, ch = getchar();
return x;
}
const int maxn = 1 << 18;
int n, q, S, bl[maxn], x[maxn], y[maxn], p[maxn]; std::vector<int> A[maxn];
long long t1[maxn], t2[maxn], ans[maxn]; std::vector<std::pair<int, int>> Q[maxn];
std::unordered_map<long long, std::pair<int, int>> pos;
long long id (int x, int y) {return x * (1LL << 30) + y;}
long long dis (int u, int v) {return 1LL * (x[u] - x[v]) * (x[u] - x[v]) + 1LL * (y[u] - y[v]) * (y[u] - y[v]);}
void add (int x, long long y) {t1[x] = std::min(t1[x], y); t2[bl[x]] = std::min(t2[bl[x]], y);}
long long ask (int x)
{
long long w = 1LL << 60;
for (int i = x; bl[i] == bl[x]; i++) w = std::min(w, t1[i]);
for (int i = bl[x] + 1; i <= bl[n]; i++) w = std::min(w, t2[i]);
return w;
}
signed main ()
{
n = read(); q = read(); S = sqrt(n);
for (int i = 1; i <= n; i++) x[i] = read(), y[i] = read(), bl[i] = (i - 1) / S + 1;
for (int i = 1, l, r; i <= q; i++) l = read(), r = read(), Q[r].push_back({l, i}), ans[i] = 1LL << 60;
for (int k = 0; k <= 27; k++)
{
std::iota(p + 1, p + n + 1, 1);
std::sort(p + 1, p + n + 1, [&] (const int &a, const int &b) {return (x[a] >> k) == (x[b] >> k) ? (y[a] >> k) < (y[b] >> k) : (x[a] >> k) < (x[b] >> k);});
for (int l = 1, r; l <= n; l = r + 1)
{
for (r = l; r < n and (x[p[r + 1]] >> k) == (x[p[l]] >> k) and (y[p[r + 1]] >> k) == (y[p[l]] >> k); r++) ;
std::sort(p + l, p + r + 1); pos[id(x[p[l]] >> k, y[p[l]] >> k)] = {l, r};
for (int i = l; i <= r; i++) for (int j = i + 1; j <= i + 3 and j <= r; j++) A[p[j]].push_back(p[i]);
}
for (int l = 1, r; l <= n; l = r + 1)
{
for (r = l; r < n and (x[p[r + 1]] >> k) == (x[p[l]] >> k) and (y[p[r + 1]] >> k) == (y[p[l]] >> k); r++) ;
std::vector<int> vec;
int px = x[p[l]] >> k, py = y[p[l]] >> k;
std::vector<std::pair<int, int>> P = {{-1, 1}, {0, 1}, {1, 1}, {1, 0}};
for (auto [dx, dy]: P) if (pos.count(id(px + dx, py + dy)))
{
auto [pl, pr] = pos[id(px + dx, py + dy)];
std::vector<int> vec;
vec.insert(vec.end(), p + l, p + r + 1);
vec.insert(vec.end(), p + pl, p + pr + 1);
std::inplace_merge(vec.begin(), vec.begin() + r - l + 1, vec.end());
for (int i = 0; i < (int)vec.size(); i++) for (int j = i + 1; j <= i + 3 and j < (int)vec.size(); j++) A[vec[j]].push_back(vec[i]);
}
}
std::unordered_map<long long, std::pair<int, int>>().swap(pos);
}
for (int i = 1; i <= n; i++) t1[i] = t2[i] = 1LL << 60;
for (int i = 1; i <= n; i++)
{
for (int p: A[i]) add(p, dis(p, i));
for (auto [p, id]: Q[i]) ans[id] = std::min(ans[id], ask(p));
}
for (int i = 1; i <= q; i++) printf("%lld\n", ans[i]);
return 0;
}