【BZOJ5317】[JSOI2018]部落战争(凸包,闵可夫斯基和)

【BZOJ5317】[JSOI2018]部落战争(凸包,闵可夫斯基和)

题面

BZOJ
洛谷

题解

很明显我们只需要两个凸包\(A,B\)
假设询问给定的方向向量是\(v\)
那么现在就是判断\(B+v\)\(A\)时候有交集。
转移一下改为判定向量\(v\)时候在\(A-B\)中,翻转\(B\)的坐标,做闵可夫斯基和得到\(A-B\)
那么每次只需要判断向量\(v\)是否在凸包内即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define MAX 100100
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
struct Point{ll x,y;double ang;};
bool operator<(Point a,Point b){return (a.ang!=b.ang)?a.ang<b.ang:a.x<b.x;}
Point operator+(Point a,Point b){return (Point){a.x+b.x,a.y+b.y};}
Point operator-(Point a,Point b){return (Point){a.x-b.x,a.y-b.y};}
Point operator*(Point a,ll b){return (Point){a.x*b,a.y*b};}
Point operator/(Point a,ll b){return (Point){a.x/b,a.y/b};}
ll operator*(Point a,Point b){return a.x*b.x+a.y*b.y;}
ll Cross(Point a,Point b){return a.x*b.y-a.y*b.x;}
ll Len(Point a){return a.x*a.x+a.y*a.y;}
ll Dis(Point a,Point b){return Len(a-b);}
struct Line{Point a,v;};
Point S[MAX<<1];int top;
void Graham(Point *p,int n)
{
	int pos=1;top=0;
	for(int i=2;i<=n;++i)
		if(p[i].x<p[pos].x||(p[i].x==p[pos].x&&p[i].y<p[pos].y))
			pos=i;
	swap(p[1],p[pos]);
	for(int i=2;i<=n;++i)p[i].ang=atan2(p[i].y-p[1].y,p[i].x-p[1].x);
	sort(&p[2],&p[n+1]);S[++top]=p[1];S[++top]=p[2];
	for(int i=3;i<=n;++i)
	{
		while(top>2&&Cross(p[i]-S[top],p[i]-S[top-1])>=0)--top;
		S[++top]=p[i];
	}
}
Point t1[MAX],t2[MAX];
void Minkowski(Point *p1,Point *p2,int n,int m)
{
	p1[n+1]=p1[1];p2[m+1]=p2[1];
	for(int i=1;i<=n;++i)t1[i]=p1[i+1]-p1[i];
	for(int i=1;i<=m;++i)t2[i]=p2[i+1]-p2[i];
	S[top=1]=p1[1]+p2[1];
	int i=1,j=1;
	while(i<=n&&j<=m)
	{
		++top;S[top]=S[top-1];
		if(Cross(t1[i],t2[j])>=0)S[top]=S[top]+t1[i++];
		else S[top]=S[top]+t2[j++];
	}
	while(i<=n)++top,S[top]=S[top-1]+t1[i++];
	while(j<=m)++top,S[top]=S[top-1]+t2[j++];	
}
int n,m,Q;
Point p1[MAX],p2[MAX],p[MAX],a,bs;
bool cmp(Point a,Point b){return Cross(a,b)>0||(Cross(a,b)==0&&Len(a)<Len(b));}
bool check(Point a)
{
	if(Cross(a,p[1])>0||Cross(p[top],a)>0)return false;
	int pos=lower_bound(&p[1],&p[top+1],a,cmp)-p-1;
	return Cross(a-p[pos],p[pos%top+1]-p[pos])<=0;
}
int main()
{
	n=read();m=read();Q=read();
	for(int i=1;i<=n;++i)p1[i].x=read(),p1[i].y=read();
	Graham(p1,n);for(int i=1;i<=top;++i)p1[i]=S[i];n=top;
	for(int i=1;i<=m;++i)p2[i].x=-read(),p2[i].y=-read();
	Graham(p2,m);for(int i=1;i<=top;++i)p2[i]=S[i];m=top;
	Minkowski(p1,p2,n,m);top-=1;bs=S[1];
	for(int i=1;i<=top;++i)p[i]=S[i]-bs;
	while(Q--)
	{
		a.x=read(),a.y=read();
		printf("%d\n",check(a-bs));
	}
	return 0;
}
posted @ 2019-01-17 15:02  小蒟蒻yyb  阅读(943)  评论(0编辑  收藏  举报