若两个凸包平移向量
w
w
w后有交,等价于
∃
a
∈
A
,
b
∈
B
,
a
=
b
+
w
exists ain A,bin B,a=b+w
∃a∈A,b∈B,a=b+w,即
∃
a
∈
A
,
b
∈
B
,
w
=
a
−
b
exists ain A,bin B, w=a-b
∃a∈A,b∈B,w=a−b,则所有
w
w
w的取值范围是
{
a
−
b
∣
a
∈
A
,
b
∈
B
}
{a-b|ain A,bin 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(qlog_2 n)
O(qlog2n)。
代码
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>usingnamespace std;#define N 200010#define ld long double#define ll long longstruct 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;}intcmp(no x, no y){if(x.y == y.y)return x.x < y.x;return x.y < y.y;}intcmp1(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;}voidsolve(){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];}}intmain(){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
");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
");elseprintf("0
");}return0;}