[JSOI2018]游戏-题解

题目地址

题意见原题面。

这个题如果学过闵可夫斯基和的话就非常好做。

直接将给出的两个点集,将其中一个坐标取反,然后先求出两个凸包,然后求这两个凸包的闵可夫斯基和,如果移动的向量组在这两个凸包的闵可夫斯基和中,那么就表示移动后会有交点,否则没有。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=1e5+10;
int n,m,Q;
ll Sqr(ll x){return x*x;}
struct Point{
	ll x,y;
	void out(){printf("WA %lld %lld\n",x,y);}
	ll len()const{return Sqr(x)+Sqr(y);}
	Point(){}
	Point(ll a,ll b):x(a),y(b){}
	void rev(){x=-x;y=-y;}
	void in(){scanf("%lld%lld",&x,&y);}
	Point operator +(const Point &a)const{return Point(x+a.x,y+a.y);}
	Point operator -(const Point &a)const{return Point(x-a.x,y-a.y);}
	bool operator <(const Point &a)const{return x<a.x||(x==a.x&&y<a.y);}
}C1[M],C2[M],H1[M],H2[M],A[M],Ls;int tot,n1,m1;
ll dot(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;}
int Convex(Point *p,Point *h,int nn){
    sort(p+1,p+n+1);int Cnt=0;
    for(int i=1;i<=nn;i++){
        while(Cnt>1&&cross(h[Cnt]-h[Cnt-1],p[i]-h[Cnt-1])<=0)--Cnt;
        h[++Cnt]=p[i];
    }	int k=Cnt;
    for(int i=nn-1;i>=1;i--){
        while(Cnt>k&&cross(h[Cnt]-h[Cnt-1],p[i]-h[Cnt-1])<=0)--Cnt;
        h[++Cnt]=p[i];
    }	if(nn>1)--Cnt;
    return Cnt;
}
void Minkovski(){
    for(int i=1;i<n1;i++) C1[i]=H1[i+1]-H1[i];C1[n1]=H1[1]-H1[n1];
    for(int i=1;i<m1;i++) C2[i]=H2[i+1]-H2[i];C2[m1]=H2[1]-H2[m1];
    A[tot=1]=H1[1]+H2[1];
    int p1=1,p2=1;
    while(p1<=n1&&p2<=m1) 
	++tot,A[tot]=A[tot-1]+(cross(C1[p1],C2[p2])>=0?C1[p1++]:C2[p2++]);
    while(p1<=n1) ++tot,A[tot]=A[tot-1]+C1[p1++];
    while(p2<=m1) ++tot,A[tot]=A[tot-1]+C2[p2++];	
}
bool cmp(const Point &a,const Point &b){return cross(a,b)>0||(cross(a,b)==0&&a.len()<b.len());}
bool isin(Point move){
    if(cross(move,C1[1])>0||cross(C1[tot],move)>0) return 0;
    int p=lower_bound(C1+1,C1+tot+1,move,cmp)-C1-1;
    return cross((move-C1[p]),(C1[p%tot+1]-C1[p]))<=0;	
}
int main(){
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1;i<=n;i++){
		C1[i].in();
	}	n1=Convex(C1,H1,n);
	for(int i=1;i<=m;i++){
		C2[i].in();C2[i].rev();
	}	m1=Convex(C2,H2,m);
	Minkovski();
	tot=Convex(A,C1,tot);
	Point st=C1[1];
	for(int i=tot;i>=1;i--)C1[i]=C1[i]-C1[1];
	while(Q--){
		Ls.in();
		printf("%d\n",isin(Ls-st));
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VictoryCzt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值