目录
大意
给2维平面上的 个点,然后进行 次询问,每次询问时提供一个点,询问该平面上有多少个包含该点 (指询问时提供的点) 的直角三角形。
输入
, 。
分析
从 最大 2000,从而排除 的纯暴力做法,考虑 时间复杂度。
考虑极角排序:
friend Point in(Point a) { auto [x, y] = a; if (x < 0 || (x == 0 && y < 0)) return Point{-x, -y}; else return Point{x, y};}friend bool operator<(Point a, Point b) { auto aa = in(a), bb = in(b); return aa.x * bb.y < aa.y * bb.x;}
可以直接使用 std::map 维护,并将 的部分都映射到平行的另一半部分,从而方便直接判断平行,并且对共线的向量直接判断相等。
第一部分
先假设每次询问的点 一定是对应直角顶点。从而预处理所有点 到点集每个点的向量,全部加入 std::map,然后对于每个 std::map 中的向量,构造对应的垂直向量tmp,使用 map.count 计算数量,时间复杂度 。
第二部分
第二部分保证每次询问的点 一定不是对应直角顶点。我们考虑离线做法。
对于给定的点集,其中的每个点 作为直角顶点,和其他的点均连出一条向量,将这些向量加入 std::map 并进行极角排序。
然后再处理每次的询问,对于每次询问的点 ,都和 构造对应垂直向量并技术,此处均与第一部分一致。时间复杂度 。
// 询问边不为直角顶点for (auto x : p) { mp.clear(); for (auto y : p) { if (x != y) { mp[x - y]++; } } for (int i = 0; i < q; i++) { auto st = x - a[i]; auto temp = Point{-st.y, st.x}; if (mp.count(temp)) ans[i] += mp[temp]; }}完整代码
#include <bits/stdc++.h>using i64 = long long;const double eps = 1e-9;constexpr i64 INF = 1e18;32 collapsed lines
struct Point { i64 x, y; Point(i64 x = 0, i64 y = 0) : x(x), y(y) {} // Point(double x = 0, double y = 0) : x(x), y(y) {} friend Point operator+(Point A, Point B) { return Point(A.x + B.x, A.y + B.y); } friend Point operator-(Point A, Point B) { return Point(A.x - B.x, A.y - B.y); } friend Point operator*(Point A, double p) { return Point(A.x * p, A.y * p); } friend Point operator/(Point A, double p) { return Point(A.x / p, A.y / p); } friend Point in(Point a) { auto [x, y] = a; if (x < 0 || (x == 0 && y < 0)) return Point{-x, -y}; else return Point{x, y}; } friend bool operator<(Point a, Point b) { auto aa = in(a), bb = in(b); return aa.x * bb.y < aa.y * bb.x; } friend i64 dot(const Point& x) { return x.x * x.x + x.y * x.y; } friend i64 dot(Point A, Point B) { return A.x * B.x + A.y * B.y; } friend double det(Point A, Point B) { return A.x * B.y - B.x * A.y; } friend bool operator==(const Point& a, const Point& b) { auto dcmp = [](double x) { if (fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; }; return !dcmp(a.x - b.x) && !dcmp(a.y - b.y); }};
inline auto read() { std::cin.tie(nullptr)->sync_with_stdio(false); return [](auto x) { return std::cin >> x, x; }(0ll);}
void solve() { int n = read(), q = read(); std::vector<Point> p(n); std::map<Point, int> mp; std::vector<Point> a(q); std::vector<int> ans(q); for (int i = 0; i < n; i++) p[i] = {read(), read()}; for (int i = 0; i < q; i++) { mp.clear(); a[i] = {read(), read()}; // 询问边为直角点 for (auto x : p) mp[x - a[i]]++;
for (auto [p, y] : mp) { auto temp = Point{-p.y, p.x}; if (mp.count(temp)) ans[i] += y * mp[temp]; } ans[i] /= 2; } // 询问边不为直角点 for (auto x : p) { mp.clear(); for (auto y : p) { if (x != y) { mp[x - y]++; } } for (int i = 0; i < q; i++) { auto st = x - a[i]; auto temp = Point{-st.y, st.x}; if (mp.count(temp)) ans[i] += mp[temp]; } } for (auto x : ans) std::cout << x << '\n';}signed main() { solve(); }