JSOI2018(战争-Minkowski sum)

给你2个点集,分别对这2个点集求凸包A,B,每次询问问凸包B平移向量 (dx.dy) ( d x . d y ) 后是否与凸包A有公共点。点集大小n,m,询问次数q的范围为1e5

b⃗ +(dx,dy)=a⃗  b → + ( d x , d y ) = a →
(dx,dy)=a⃗ b⃗  ( d x , d y ) = a → − b →
我们定义向量集合A,B的Minkowski sum为 A+B={a+b|aA,bB} A + B = { a + b | a ∈ A , b ∈ B }
因此合法的 (dx,dy) ( d x , d y ) 范围为:A和-B(B集合所有向量取反)的Minkowski sum
在维基百科上有Minkowski addition的线性做法

For two convex polygons P and Q in the plane with m and n vertices, their Minkowski sum is a convex polygon with at most m + n vertices and may be computed in time O (m + n) by a very simple procedure, which may be informally described as follows. Assume that the edges of a polygon are given and the direction, say, counterclockwise, along the polygon boundary. Then it is easily seen that these edges of the convex polygon are ordered by polar angle. Let us merge the ordered sequences of the directed edges from P and Q into a single ordered sequence S. Imagine that these edges are solid arrows which can be moved freely while keeping them parallel to their original direction. Assemble these arrows in the order of the sequence S by attaching the tail of the next arrow to the head of the previous arrow. It turns out that the resulting polygonal chain will in fact be a convex polygon which is the Minkowski sum of P and Q.

#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
#define gmax(a,b) a=max(a,b)
#define ALL(x) (x).begin(),(x).end()
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
class P{
public:
    ll x,y;
    P(ll x=0,ll y=0):x(x),y(y){}

    friend P operator- (P A,P B) { return P(A.x-B.x,A.y-B.y); }
    friend P operator+ (P A,P B) { return P(A.x+B.x,A.y+B.y); }
    friend P operator* (P A,ll p) { return P(A.x*p,A.y*p); }
    friend P operator/ (P A,ll p) { return P(A.x/p,A.y/p); }
    friend bool operator< (const P& a,const P& b) {return a.x-b.x<0 ||(a.x==b.x&& a.y<b.y );}
}; 
P read_point() {
    P a;
    a.x=read(),a.y=read();
    return a;   
} 
bool operator==(const P& a,const P& b) {
    return a.x==b.x&&a.y==b.y;
} 
typedef P V;
ll cross(V a,V b) {
    return a.x*b.y-a.y*b.x;
}

void print(double a) {
    printf("%.6lf",a); 
}
void print(P p) {
    printf("(%.6lf,%.6lf)",p.x,p.y);
}
template<class T>
void print(vector<T> v) {
    sort(v.begin(),v.end());
    putchar('[');
    int n=v.size();
    Rep(i,n) {
        print(v[i]);
        if (i<n-1) putchar(','); 
    }
    puts("]");
}

typedef vector<P> Polygon ;
bool isPointInConvex(P p,Polygon poly){ // Counterclockwise  inside 1 outside 0
    int n=SI(poly);
    if(n<3) return 0;
    if(cross(p-poly[0],poly[1]-poly[0])>=0) return 0;
    if(cross(p-poly[0],poly[n-1]-poly[0])<=0) return 0;

    int i=2,j=n-1;
    int line=-1;
    while(i<=j) {
        int mid=(i+j)>>1;
        if(cross(p-poly[0],poly[mid]-poly[0])>=0) {
            line=mid;
            j=mid-1;
        }
        else i=mid+1;
    }
    return cross(p-poly[line-1],poly[line]-poly[line-1])<0;
}

bool isPointInConvex2(P p,Polygon &poly){ // Counterclockwise  inside or edge 1 outside 0
    int n=SI(poly);
    if(cross(p-poly[0],poly[1]-poly[0])>0) return 0;
    if(cross(p-poly[0],poly[n-1]-poly[0])<0) return 0;
    int i=2,j=n-1;
    int line=-1;
    while(i<=j) {
        int mid=(i+j)>>1;
        if(cross(p-poly[0],poly[mid]-poly[0])>=0) {
            line=mid;
            j=mid-1;
        }
        else i=mid+1;
    }
    return cross(p-poly[line-1],poly[line]-poly[line-1])<=0;
}
int ConvexHull(P *p,int n,P *ch) {
    sort(p,p+n);
    int m=0;
    Rep(i,n) {
        while(m>1 && cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
        ch[m++]=p[i];
    }
    int k=m;
    RepD(i,n-2) {
        while(m>k && cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
        ch[m++]=p[i];
    }
    if ( n > 1 ) m--;
    return m;
}
void simplify(Polygon& poly) {
    Polygon ans;
    int n=SI(poly);
    Rep(i,n) {
        if (cross(poly[i]-poly[(i+1)%n],poly[(i+1)%n]-poly[(i+2)%n])!=0)
            ans.pb(poly[(i+1)%n]);
    }
    n=SI(ans);
}

int n,m,q;
Polygon a,b;
bool AngleCmp(V a,V b){
    return atan2(a.y,a.x)<atan2(b.y,b.x);
}
Polygon Minkowski_addition(Polygon a,Polygon b) {//clockwise
    vector<V> v;
    int n=SI(a),m=SI(b);
    Rep(i,n) {
        v.pb(a[(i+1)%n]-a[i]);
    }
    Rep(i,m) {
        v.pb(b[(i+1)%m]-b[i]);
    }
    sort(ALL(v),AngleCmp);
    v.resize(n+m);

    ll mya=a[0].y;
    Rep(i,n) gmax(mya,a[i].y);
    ll myb=b[0].y;
    Rep(i,m) gmax(myb,b[i].y);
    ll mxa=a[0].x;
    Rep(i,n) gmax(mxa,a[i].x);
    ll mxb=b[0].x;
    Rep(i,m) gmax(mxb,b[i].x);

    For(i,n+m-1) {
        v[i]=v[i]+v[i-1];
    }
    ll vx=v[0].x,vy=v[0].y;
    For(i,n+m-1) {
        gmax(vx,v[i].x);
        gmax(vy,v[i].y);
    }
    P vv=P(mxa+mxb-vx,mya+myb-vy);
    Rep(i,n+m) v[i]=v[i]+vv;    
    return v;
}
#define MAXN (1033456)
P p[MAXN],ch[MAXN];
int main()
{
//  freopen("war10.in","r",stdin);
//  freopen("war.out","w",stdout);
    cin>>n>>m>>q;
//  int st=clock();
    Rep(i,n) p[i]=read_point();
    n=ConvexHull(p,n,ch);   
    Rep(i,n) a.pb(ch[i]);

    Rep(i,m) p[i]=read_point();
    Rep(i,m) p[i].x*=-1,p[i].y*=-1;
    m=ConvexHull(p,m,ch);   
    Rep(i,m) b.pb(ch[i]);
    Polygon c= Minkowski_addition(a,b);
    simplify(c);
    For(i,q) {
        P q;q.x=read(),q.y=read();
        int d=isPointInConvex2(q,c);
        printf("%d\n",d);
    }
//  cerr<<(double)(clock()-st)/CLOCKS_PER_SEC<<endl;
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值