JSOI2018 战争(凸包+闵可夫斯基和)
JSOI2018 战争
题解
- 每次询问暴力判断时间无法满足,考虑是否可以求出使两凸包有交或无交的向量所在的范围。
- 若两个凸包平移向量 w w w后有交,等价于 ∃ a ∈ A , b ∈ B , a = b + w \exists a\in A,b\in B,a=b+w ∃a∈A,b∈B,a=b+w,即 ∃ a ∈ A , b ∈ B , w = a − b \exists a\in A,b\in B, w=a-b ∃a∈A,b∈B,w=a−b,则所有 w w w的取值范围是 { a − b ∣ a ∈ A , b ∈ B } \{a-b|a\in A,b\in B\} {a−b∣a∈A,b∈B},把 b b b向量全部取反,和 a a a做一遍闵可夫斯基和得到的凸包就是能使两凸包有交的向量范围(包括凸包的边)。
- 最后只需要判断向量是否在凸包上,如果用回转数或光线投射复杂度是 O ( n q ) O(nq) O(nq)的,可以先把凸包最左下角的点平移到 ( 1 , 1 ) (1,1) (1,1),二分出该向量的极角序在哪两个顶点之间,然后判断该向量是否在这两个向量和 ( 1 , 1 ) (1,1) (1,1)构成的三角形内,复杂度降为 O ( q log 2 n ) O(q\log_2 n) O(qlog2n)。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 200010
#define ld long double
#define ll long long
struct no {
ll x, y, s;
ld d;
}a[N], b[N], a0[N], b0[N], q[N];
int n, m, t;
ll sqr(ll x) {
return x * x;
}
int cmp(no x, no y) {
if(x.y == y.y) return x.x < y.x;
return x.y < y.y;
}
int cmp1(no x, no y) {
if(x.d == y.d) return x.s > y.s;
return x.d < y.d;
}
no in(no x, no y) {
return {x.x + y.x, x.y + y.y};
}
no de(no x, no y) {
return {x.x - y.x, x.y - y.y};
}
ll ct(no x, no y) {
return x.x * y.y - x.y * y.x;
}
void solve() {
int i;
sort(a + 1, a + n + 1, cmp);
for(i = 2; i <= n; i++) {
a[i].d = atan2(a[i].y - a[1].y, a[i].x - a[1].x);
a[i].s = sqr(a[i].y - a[1].y) + sqr(a[i].x - a[1].x);
}
sort(a + 2, a + n + 1, cmp1);
t = 1;
q[1] = a[1];
for(i = 2; i <= n; i++) if(i == 2 || a[i].d != a[i - 1].d) {
while(t > 1 && ct(de(q[t], q[t - 1]), de(a[i], q[t])) < 0) t--;
q[++t] = a[i];
}
}
int main() {
int Q, i;
scanf("%d%d%d", &n, &m, &Q);
for(i = 1; i <= n; i++) {
scanf("%lld%lld", &a[i].x, &a[i].y);
}
for(i = 1; i <= m; i++) {
scanf("%lld%lld", &b[i].x, &b[i].y);
b[i].x = -b[i].x, b[i].y = -b[i].y;
}
solve();
int at = t;
for(i = 1; i <= t; i++) a0[i] = q[i];
n = m;
for(i = 1; i <= m; i++) a[i] = b[i];
solve();
int bt = t;
for(i = 1; i <= t; i++) b0[i] = q[i];
int tot = 0;
for(i = 1; i <= at; i++) {
a[++tot] = de(a0[i % at + 1], a0[i]);
a[tot].d = atan2(a[tot].y, a[tot].x);
if(a[tot].d < 0) a[tot].d += M_PI * 2.0;
}
for(i = 1; i <= bt; i++) {
a[++tot] = de(b0[i % bt + 1], b0[i]);
a[tot].d = atan2(a[tot].y, a[tot].x);
if(a[tot].d < 0) a[tot].d += M_PI * 2.0;
}
sort(a + 1, a + tot + 1, cmp1);
q[1] = in(a0[1], b0[1]);
for(i = 1; i < tot; i++) q[i + 1] = in(q[i], a[i]);
for(i = 2; i <= tot; i++) {
q[i].d = atan2(q[i].y - q[1].y, q[i].x - q[1].x);
}
while(Q--) {
no x;
scanf("%lld%lld", &x.x, &x.y);
x.d = atan2(x.y - q[1].y, x.x - q[1].x);
if(x.d > q[tot].d || x.d < 0) {
printf("0\n");
continue;
}
int l = 1, r = tot - 1, s;
while(l <= r) {
int mid = (l + r) / 2;
if(x.d >= q[mid].d) s = mid, l = mid + 1; else r = mid - 1;
}
if(ct(de(x, q[s]), de(q[s + 1], x)) <= 0) printf("1\n"); else printf("0\n");
}
return 0;
}
哈哈哈哈哈哈哈哈哈哈

浙公网安备 33010602011771号