zoukankan      html  css  js  c++  java
  • 【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
    ",check(a-bs));
    	}
    	return 0;
    }
    
  • 相关阅读:
    当函数模版遇上函数重载
    <h2>1. mongodb介绍</h2>
    Your algorithm's runtime complexity must be in the order of O(log n).
    item.imageInsets =
    JobService和JobScheduler机制在Android5.0以上保活
    PL/SQL精明的调用栈分析
    HQL查询步骤
    OSGI项目中获取文件路径
    int *p,cons int *p,int const *p,int * const p,const int * const p,int const * const p的差别
    通过 KVM+virt-manager配置双屏虚拟机(两套键盘。鼠标)
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10282297.html
Copyright © 2011-2022 走看看