LG P4557 [JSOI2018]战争
Description
九条可怜是一个热爱读书的女孩子。
在她最近正在读的一本小说中,描述了两个敌对部落之间的故事。第一个部落有 $n$ 个人,第二个部落有 $m$ 个人,每一个人的位置可以抽象成二维平面上坐标为 $(x_i,y_i)$的点。
在这本书中,人们有很强的领地意识,对于平面上的任何一个点,如果它被三个来自同一部落的人形成的三角形(可能退化成一条线段)包含(包括边界),那么这一个点就属于这一个部落的领地。如果存在一个点同时在两个阵营的领地中,那么这两个部落就会为了争夺这一个点而发生战争。
常年的征战让两个部落不堪重负,因此第二个部落的族长作出了一个英明的决定,他打算选择一个向量 $(dx,dy)$ ,让所有的族人都迁徙这个向量的距离,即所有第二阵营的人的坐标都变成 $(x_i+dx,y_i+dy)$
现在他计划了 $q$ 个迁徙的备选方案,他想要你来帮忙对每一个迁徙方案,计算一下在完成了迁徙之后,两个部落之间还会不会因为争夺领地而发生战争。
Solution
要求求出B凸包向指定方向移动一段距离是否与A凸包有交
考虑如果有交,那么存在$b+w=a$
整理得$w=a-b$,即为两个凸包的闵科夫斯基和
代码中的in函数有些bug
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<algorithm> #include<iostream> #include<cstdio> #include<cmath> using namespace std; int n,m,q,tot,top; struct Node{ long long x,y; Node operator +(const Node &z)const{return (Node){x+z.x,y+z.y};} Node operator -(const Node &z)const{return (Node){x-z.x,y-z.y};} long long operator *(const Node &z)const{return x*z.y-y*z.x;} long long dis(){return x*x+y*y;} }A[100005],B[100005],base,sta[100005],s1[100005],s2[100005],s[200005]; inline int read(){ int f=1,w=0; char ch=0; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); return f*w; } bool cmp(Node a,Node b){return a*b>0||!(a*b)&&a.dis()<b.dis();} void Graham(Node *a,int &N){ int k=1; for(int i=2;i<=N;i++)if(a[i].y<a[k].y||a[i].y==a[k].y&&a[i].x<a[k].x)k=i; swap(a[k],a[1]),base=a[1]; for(int i=1;i<=N;i++)a[i]=a[i]-base; sort(a+2,a+N+1,cmp),top=2,sta[1]=a[1],sta[2]=a[2]; for(int i=3;i<=N;i++){ while(top>=2&&(sta[top]-sta[top-1])*(a[i]-sta[top-1])<=0)--top; sta[++top]=a[i]; } for(int i=1;i<=top;i++)a[i]=sta[i]+base; N=top; } void Minkowski(){ for(int i=1;i<n;i++)s1[i]=A[i+1]-A[i];s1[n]=A[1]-A[n]; for(int i=1;i<m;i++)s2[i]=B[i+1]-B[i];s2[m]=B[1]-B[m]; s[tot=1]=A[1]+B[1]; int pos1=1,pos2=1; while(pos1<=n&&pos2<=m)++tot,s[tot]=s[tot-1]+(s1[pos1]*s2[pos2]>=0?s1[pos1++]:s2[pos2++]); while(pos1<=n)++tot,s[tot]=s[tot-1]+s1[pos1++]; while(pos2<=m)++tot,s[tot]=s[tot-1]+s2[pos2++]; } bool in(Node x){ if(x*s[1]>0||s[tot]*x>0)return false; int temp=lower_bound(s+1,s+tot+1,x,cmp)-s-1; return (x-s[temp])*(s[temp%tot+1]-s[temp])<=0; } int main(){ n=read(),m=read(),q=read(); for(int i=1;i<=n;i++)A[i]=(Node){read(),read()}; for(int i=1;i<=m;i++)B[i]=(Node){-read(),-read()}; Graham(A,n),Graham(B,m),Minkowski(),Graham(s,tot),base=s[1]; for(int i=1;i<=tot;i++)s[i]=s[i]-base; for(;q;q--)s[0]=(Node){read(),read()},printf("%d\n",in(s[0]-base)); return 0; }