zoukankan      html  css  js  c++  java
  • BZOJ5317 JSOI2018部落战争(凸包)

      即询问凸包是否有交。这显然可以直接求半平面交,但是复杂度O(q(n+m)),且没有什么优化空间。

      更直接地表示,即相当于询问是否存在点a∈A,b∈B,使得a+d=b。移项,得到d=b-a。可以发现等式右边是一个闵可夫斯基和。求闵可夫斯基和只需要分别求出两个凸包,然后每次考虑ai+1+bi和ai+bi+1哪个将作为凸包中下一个点。将其求出后,只需要判断点是否在凸包内。二分找到上下边界即可。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    using namespace std;
    #define ll long long
    #define vector point
    #define N 200010
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,q;
    const double eps=1E-8;
    struct point
    {
        int x,y;
        vector operator +(const vector&a) const
        {
            return (vector){x+a.x,y+a.y};
        }
        vector operator -(const vector&a) const
        {
            return (vector){x-a.x,y-a.y};
        }
        ll operator *(const vector&a) const
        {
            return 1ll*x*a.y-1ll*y*a.x;
        }
        bool operator <(const point&a) const
        {
            return x<a.x||x==a.x&&y<a.y;
        }
    }a[N],b[N],c[N],d[N],e[N],f[N];
    struct line
    {
        point a;vector p;
        double f(int x){return a.y+(double)(x-a.x)/p.x*p.y;}
    };
    void makehull(point *hull,point *a,int &n)
    {
        sort(a+1,a+n+1);hull[1]=a[1];
        int m=1;
        for (int i=2;i<=n;i++)
        {
            while (m>1&&(a[i]-hull[m-1])*(hull[m]-hull[m-1])>0) m--;
            hull[++m]=a[i];
        }
        for (int i=n-1;i>=1;i--)
        {
            while (m>1&&(a[i]-hull[m-1])*(hull[m]-hull[m-1])>0) m--;
            hull[++m]=a[i];
        }
        n=m;
    }
    void merge(point *up,point *down,point *a,point *b,int &n,int &m)
    {
        int p=1,u=1,v=1;up[1]=a[1]+b[1];
        while (u<n||v<m)
        {
            if (u==n) v++;
            else if (v==m) u++;
            else if ((a[u+1]+b[v]-up[p])*(a[u]+b[v+1]-up[p])>0) u++;else v++;
            while (p>1&&(a[u]+b[v]-up[p-1])*(up[p]-up[p-1])>0) p--;
            up[++p]=a[u]+b[v];
        }
        for (int i=1;i<=p;i++) if (up[i].x>up[i+1].x) {n=i;break;}
        for (int i=n;i<=p;i++) down[i-n+1]=up[i];m=p-n+1;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5317.in","r",stdin);
        freopen("bzoj5317.out","w",stdout);
    #endif
        n=read(),m=read(),q=read();
        for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
        for (int i=1;i<=m;i++) b[i].x=-read(),b[i].y=-read();
        makehull(c,a,n),makehull(d,b,m);
        merge(e,f,c,d,n,m);reverse(f+1,f+m+1);
        for (int i=1;i<=q;i++)
        {
            int x=read(),y=read();
            int u=lower_bound(e+1,e+n+1,(point){x,y})-e;
            if (u==1||u==n+1||(line){e[u-1],e[u]-e[u-1]}.f(x)-eps>y) {printf("0
    ");continue;}
            u=lower_bound(f+1,f+m+1,(point){x,y})-f;
            if (u==1||u==m+1||(line){f[u-1],f[u]-f[u-1]}.f(x)+eps<y) {printf("0
    ");continue;}
            printf("1
    ");
        }
        return 0;
    }
  • 相关阅读:
    PHP操作数据库
    ANE打包
    我的C++笔记(数据的共享与保护)
    js 正计时和倒计时
    JAVA 日期 一个时间段总共几周,每一天星期几
    mybatis 处理in
    freemarker
    正则手机验证,身份证验证
    签到
    spring定时器
  • 原文地址:https://www.cnblogs.com/Gloid/p/10257161.html
Copyright © 2011-2022 走看看