即询问凸包是否有交。这显然可以直接求半平面交,但是复杂度O(q(n+m)),且没有什么优化空间。
更直接地表示,即相当于询问是否存在点a∈A,b∈B,使得a+d=b。移项,得到d=b-a。可以发现等式右边是一个闵可夫斯基和。求闵可夫斯基和只需要分别求出两个凸包,然后每次考虑ai+1+bi和ai+bi+1哪个将作为凸包中下一个点。将其求出后,只需要判断点是否在凸包内。二分找到上下边界即可。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #include<cassert> using namespace std; #define ll long long #define vector point #define N 200010 int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,q; const double eps=1E-8; struct point { int x,y; vector operator +(const vector&a) const { return (vector){x+a.x,y+a.y}; } vector operator -(const vector&a) const { return (vector){x-a.x,y-a.y}; } ll operator *(const vector&a) const { return 1ll*x*a.y-1ll*y*a.x; } bool operator <(const point&a) const { return x<a.x||x==a.x&&y<a.y; } }a[N],b[N],c[N],d[N],e[N],f[N]; struct line { point a;vector p; double f(int x){return a.y+(double)(x-a.x)/p.x*p.y;} }; void makehull(point *hull,point *a,int &n) { sort(a+1,a+n+1);hull[1]=a[1]; int m=1; for (int i=2;i<=n;i++) { while (m>1&&(a[i]-hull[m-1])*(hull[m]-hull[m-1])>0) m--; hull[++m]=a[i]; } for (int i=n-1;i>=1;i--) { while (m>1&&(a[i]-hull[m-1])*(hull[m]-hull[m-1])>0) m--; hull[++m]=a[i]; } n=m; } void merge(point *up,point *down,point *a,point *b,int &n,int &m) { int p=1,u=1,v=1;up[1]=a[1]+b[1]; while (u<n||v<m) { if (u==n) v++; else if (v==m) u++; else if ((a[u+1]+b[v]-up[p])*(a[u]+b[v+1]-up[p])>0) u++;else v++; while (p>1&&(a[u]+b[v]-up[p-1])*(up[p]-up[p-1])>0) p--; up[++p]=a[u]+b[v]; } for (int i=1;i<=p;i++) if (up[i].x>up[i+1].x) {n=i;break;} for (int i=n;i<=p;i++) down[i-n+1]=up[i];m=p-n+1; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5317.in","r",stdin); freopen("bzoj5317.out","w",stdout); #endif n=read(),m=read(),q=read(); for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(); for (int i=1;i<=m;i++) b[i].x=-read(),b[i].y=-read(); makehull(c,a,n),makehull(d,b,m); merge(e,f,c,d,n,m);reverse(f+1,f+m+1); for (int i=1;i<=q;i++) { int x=read(),y=read(); int u=lower_bound(e+1,e+n+1,(point){x,y})-e; if (u==1||u==n+1||(line){e[u-1],e[u]-e[u-1]}.f(x)-eps>y) {printf("0 ");continue;} u=lower_bound(f+1,f+m+1,(point){x,y})-f; if (u==1||u==m+1||(line){f[u-1],f[u]-f[u-1]}.f(x)+eps<y) {printf("0 ");continue;} printf("1 "); } return 0; }