• P4557[JSOI2018]战争【凸包,闵可夫斯基和】


    正题

    题目连接:https://www.luogu.com.cn/problem/P4557


    题目大意

    给出两个点集\(A,B\)\(q\)次询问给出一个向量\(v\),询问将\(B\)中所有点加上向量\(v\)后两个集合的凸包是否有交。

    \(1\leq n,m,q\leq 10^5\)


    解题思路

    闵可夫斯基和定义了两个向量集合的和,这里只讨论凸包的闵可夫斯基和。

    \(A+B\),那么相当于以\(A\)凸包绕着\(B\)的凸包跑一圈形成的图形(位置不重要,这里的都是相对位置)。

    然后求法就是实际上求和后的每条边是由原来的边组成的一个大凸包,所以我们直接把原来的两个凸包的边归并排序,然后再逐一算出每个点的位置就好了。

    然后这个东西有什么用的,我也不知道。

    但是看这道题,我们求出\(A+(-B)\),这样就大致\(A\)\(B\)的位置的形状,此时对于询问向量\(v\),如果它在\(A+(-B)\)内那么就是有交的,否则就是无交的。

    时间复杂度:\(O(n\log n)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define ll long long
    using namespace std;
    const ll N=1e5+10;
    struct vec{
    	ll x,y;
    	vec(ll xx=0,ll yy=0)
    	{x=xx;y=yy;return;}
    	ll len(){return x*x+y*y;}
    }a[N],b[N],c[N],d[N],p[N<<1];
    ll n,m,q,tot;
    vector<vec> s;
    vec operator+(const vec &a,const vec &b)
    {return vec(a.x+b.x,a.y+b.y);}
    vec operator-(const vec &a,const vec &b)
    {return vec(a.x-b.x,a.y-b.y);}
    ll operator^(const vec &a,const vec &b)
    {return a.x*b.y-a.y*b.x;}
    bool cmp(vec x,vec y)
    {return (x.x==y.x)?(x.y<y.y):(x.x<y.x);}
    bool cMp(vec x,vec y)
    {return (x^y)>0||((x^y)==0&&x.len()<y.len());}
    #define top (s.size()-1)
    void Convex(vec *p,ll &n){
    	while(!s.empty())s.pop_back();
    	sort(p+1,p+1+n,cmp);vec bas=p[1];
    	for(ll i=1;i<=n;i++)p[i]=p[i]-bas;
    	sort(p+2,p+1+n,cMp);s.push_back(p[1]);
    	for(ll i=2;i<=n;i++){
    		while(top>0&&((s[top]-s[top-1])^(p[i]-s[top-1]))<=0)s.pop_back();
    		s.push_back(p[i]);
    	}
    	for(ll i=0;i<=top;i++)p[i+1]=s[i]+bas;
    	n=s.size();return;
    }
    #undef top
    void Minkowski(){
    	for(ll i=1;i<n;i++)c[i]=a[i+1]-a[i];c[n]=a[1]-a[n];
    	for(ll i=1;i<m;i++)d[i]=b[i+1]-b[i];d[m]=b[1]-b[m];
    	ll l=1,r=1;p[1]=a[1]+b[1];tot=1;
    	while(l<=n&&r<=m)
    		tot++,p[tot]=p[tot-1]+(((c[l]^d[r])>=0)?c[l++]:d[r++]);
    	while(l<=n)tot++,p[tot]=p[tot-1]+c[l++];
    	while(r<=m)tot++,p[tot]=p[tot-1]+d[r++];
    	return;
    }
    bool Inside(vec x){
    	if((x^p[1])>0||(x^p[tot])<0)return 0;
    	ll pos=lower_bound(p+1,p+1+tot,x,cMp)-p-1;
    	return ((x-p[pos])^(p[pos%tot+1]-p[pos]))<=0;
    }
    signed main()
    {
    	scanf("%lld%lld%lld",&n,&m,&q);
    	for(ll i=1;i<=n;i++)scanf("%lld%lld",&a[i].x,&a[i].y);
    	for(ll i=1;i<=m;i++)scanf("%lld%lld",&b[i].x,&b[i].y),b[i]=vec(0,0)-b[i];
    	Convex(a,n);Convex(b,m);
    	Minkowski();
    	Convex(p,tot);
    	vec bas=p[1];
    	for(ll i=1;i<=tot;i++)p[i]=p[i]-bas;
    	while(q--){
    		vec x;
    		scanf("%lld%lld",&x.x,&x.y);
    		printf("%lld\n",Inside(x-bas));
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java 中位移运算符 >>,>>>,<<
    HashMap 源码解读
    CentOS 配置防火墙操作实例(启、停、开、闭端口)
    CentOS 配置防火墙操作实例(启、停、开、闭端口)
    js实现页面重新加载
    js实现页面重新加载
    关于Ajax的技术组成与核心原理
    关于Ajax的技术组成与核心原理
    PHP水印制作
    PHP水印制作
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/16250872.html
Copyright © 2020-2023  润新知