[JSOI2018]战争

题目

闵可夫斯基和啊

定义点集\(A\)和点集\(B\)的闵可夫斯基和为\(\{a+b|a\in A,b\in B\}\)

下面只讨论凸包的闵可夫斯基和

由于凸包的凸性,所以两个凸包的闵可夫斯基和等价于把其中一个凸包绕另一个凸包的边移动的过程中扫过的区域,更强的性质是,两个闵可夫斯基和与它们的每一条边按极角序顺次相连所得的图形都是等价的,于是我们把两个凸包的左下角加起来,这就是新的凸包的左下角;之后把两个凸包的边都搞出来,按照极角序归并就好了

可能有三点共线的情况,于是可以对新得到的点再求一个凸包

对于这道题,移动\(v\)后有交点等价于存在\(a\in A,b\in B\)满足\(a=b+v\),即\(a-b=v\)

所以我们可以把\(B\)上的点取反,求一下闵可夫斯基和,之后只需要判断\(v\)是否在这个凸包里就好了

判断一个点是否在凸包里我们可以二分找到最后一个极角序小于它的点,之后用叉积判断就好了

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
inline LL read() {
    char c=getchar();LL x=0,r=1;while(c<'0'||c>'9'){if(c=='-')r=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3ll)+(x<<1ll)+c-48,c=getchar();return x*r;
}
const int maxn=1e5+5;
int n,m,q,len,top;
struct node{LL x,y;}a[maxn],b[maxn],c[maxn<<1],st[maxn<<1],va[maxn],vb[maxn],T,K;
inline node operator+(node A,node B){return (node){A.x+B.x,A.y+B.y};}
inline node operator-(node A,node B) {return (node){A.x-B.x,A.y-B.y};}
inline LL operator*(node A,node B) {return A.x*B.y-A.y*B.x;}
inline LL Len(node A) {return A.x*A.x+A.y*A.y;}
inline int cmp(node A,node B) {return (A-T)*(B-T)==0?Len(A-T)<Len(B-T):(A-T)*(B-T)>0;}
inline void Get(node *A,int n) {
    top=0;T.x=1e18,T.y=1e18;
    for(re int i=1;i<=n;i++) {
        if(A[i].x<T.x) T=A[i];
        else if(A[i].x==T.x&&A[i].y<T.y) T=A[i];
    }
    std::sort(A+1,A+n+1,cmp);st[top=1]=A[1];
    for(re int i=2;i<=n;i++) {
        while(top>1&&(A[i]-st[top-1])*(st[top]-st[top-1])>=0) --top;
        st[++top]=A[i];
    }
    for(re int i=1;i<=top;i++) A[i]=st[i];
}
inline void minkowski(node *A,node *B,int n,int m) {
    for(re int i=1;i<n;i++) va[i]=A[i+1]-A[i];va[n]=A[1]-A[n];
    for(re int i=1;i<m;i++) vb[i]=B[i+1]-B[i];vb[m]=B[1]-B[m];
    c[top=1]=A[1]+B[1];int ta=1,tb=1;
    while(ta<=n&&tb<=m) c[top+1]=c[top]+(va[ta]*vb[tb]>=0?va[ta++]:vb[tb++]),++top;
    while(ta<=n) c[top+1]=c[top]+va[ta++],++top;
    while(tb<=m) c[top+1]=c[top]+vb[tb++],++top;
}
inline int in(node dr,node *A) {
    if(dr*A[1]>0||A[len]*dr>0) return 0;
    int l=1,r=len,nw=0;T.x=0,T.y=0;
    while(l<=r) {
        int mid=l+r>>1;
        if(cmp(A[mid],dr)) nw=mid,l=mid+1;else r=mid-1;
    }
    return (dr-A[nw])*(A[nw%len+1]-A[nw])<=0;
}
int main() {
    n=read();m=read(),q=read();
    for(re int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
    for(re int i=1;i<=m;i++) b[i].x=-read(),b[i].y=-read();
    Get(a,n);n=top;Get(b,m),m=top;
    minkowski(a,b,n,m);len=top;Get(c,len);len=top;
    for(re int i=len;i>1;i--) c[i]=c[i]-c[1];K=c[1];c[1]=c[1]-c[1];
    for(node dr;q;--q) {
        dr.x=read(),dr.y=read();
        printf("%d\n",in(dr-K,c));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/12009845.html