【题目链接】
【思路要点】
- 询问点\(c=(x,y)\)的答案为1当且仅当\(c\in \{a+(-b)|a\in A,b\in B\}\)。
- 求解两个点集凸包的闵可夫斯基和,然后判断询问点是否在求得的凸包中即可。
- 时间复杂度\(O(NLogN)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 5; const double eps = 1e-11; template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } struct point {int x, y; }; point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; } point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; } point operator * (point a, int b) {return (point) {a.x * b, a.y * b}; } long long operator * (point a, point b) {return 1ll * a.x * b.y - 1ll * a.y * b.x; } bool operator < (point a, point b) { if (a.y == b.y) return a.x < b.x; else return a.y < b.y; } long long dist(point a) {return 1ll * a.x * a.x + 1ll * a.y * a.y; } int n, m, q; point a[MAXN], b[MAXN], c[MAXN], fp; bool cmp(point a, point b) { long long tmp = (a - fp) * (b - fp); if (tmp == 0) return dist(a - fp) < dist(b - fp); else return tmp > 0; } int main() { read(n), read(m), read(q); for (int i = 1; i <= n; i++) read(a[i].x), read(a[i].y); for (int i = 2; i <= n; i++) if (a[i] < a[1]) swap(a[i], a[1]); fp = a[1]; sort(a + 2, a + n + 1, cmp); a[++n] = a[1]; int top = 1; for (int i = 2; i <= n; i++) { while (top >= 2 && (a[top] - a[top - 1]) * (a[i] - a[top - 1]) <= 0) top--; a[++top] = a[i]; } n = top; for (int i = 1; i <= m; i++) { read(b[i].x), read(b[i].y); b[i] = b[i] * (-1); } for (int i = 2; i <= m; i++) if (b[i] < b[1]) swap(b[i], b[1]); fp = b[1]; sort(b + 2, b + m + 1, cmp); b[++m] = b[1]; top = 1; for (int i = 2; i <= m; i++) { while (top >= 2 && (b[top] - b[top - 1]) * (b[i] - b[top - 1]) <= 0) top--; b[++top] = b[i]; } m = top; int pn = 1, pm = 1; c[1] = a[1] + b[1]; for (int i = 2; i <= n + m - 1; i++) { if (pn == n) { point tmp = b[pm + 1] - b[pm]; pm++; c[i] = c[i - 1] + tmp; } else if (pm == m) { point tmp = a[pn + 1] - a[pn]; pn++; c[i] = c[i - 1] + tmp; } else { point tmp = a[pn + 1] - a[pn], tnp = b[pm + 1] - b[pm]; if (tmp * tnp >= 0) c[i] = c[i - 1] + tmp, pn++; else c[i] = c[i - 1] + tnp, pm++; } } n = n + m - 1; top = 1; for (int i = 2; i <= n; i++) { while (top >= 2 && (c[top] - c[top - 1]) * (c[i] - c[top - 1]) <= 0) top--; c[++top] = c[i]; } n = top; for (int i = 2; i <= n - 1; i++) if (c[i].y >= c[i - 1].y && c[i].y >= c[i + 1].y) { m = i; break; } for (int i = 1; i <= q; i++) { point pos; read(pos.x), read(pos.y); if (pos.y < c[1].y || pos.y > c[m].y) { printf("0\n"); continue; } if (pos.y == c[1].y) { int vl = c[1].x, vr = c[1].x; if (pos.y == c[2].y) vr = c[2].x; printf("%d\n", pos.x >= vl && pos.x <= vr); continue; } if (pos.y == c[m].y) { int vl = c[m].x, vr = c[m].x; if (pos.y == c[m + 1].y) vl = c[m + 1].x; printf("%d\n", pos.x >= vl && pos.x <= vr); continue; } double vl, vr; int l = 1, r = m; while (l < r) { int mid = (l + r + 1) / 2; if (c[mid].y <= pos.y) l = mid; else r = mid - 1; } vr = c[l].x + (double) (c[l + 1].x - c[l].x) / (c[l + 1].y - c[l].y) * (pos.y - c[l].y); l = m, r = n; while (l < r) { int mid = (l + r + 1) / 2; if (c[mid].y >= pos.y) l = mid; else r = mid - 1; } vl = c[l].x + (double) (c[l + 1].x - c[l].x) / (c[l + 1].y - c[l].y) * (pos.y - c[l].y); printf("%d\n", pos.x >= vl - eps && pos.x <= vr + eps); } return 0; }