闵可夫斯基和简介

两个凸包 \(A,B\),分别有 \(n,m\) 个端点,记 \(a\in A\) 表示点 \(a\) 在多边形内(含边界),\(A\)\(B\) 的闵可夫斯基和定义为(\(a+b\) 表示向量相加):

\[C=\{a+b|a\in A,b\in B\} \]

使用反证法和肉眼观察尝试法不难得出:

  • \(C\) 是凸包
  • \(C\) 的边(共 \(n+m\) 条)是由原 \(A,B\) 的边一一平移得来

故:对 \(A,B\) 极角排序,得到它们的边集,并起来,按极角排序,按时针方向依次就是 \(C\) 的边集。

形状知道了,位置在哪里?
我的做法是求出 \(mnax,mnay,mnbx,mnby\),那么不难发现 \(mn(A+B)_{实际}x=mnax+mnbx,mn(A+B)_{实际}y=mnay+mnby\)

练习:[JSOI2018]战争
\(\exists b,b+\overrightarrow x\in A\iff x\in A-B\)
所以要干两件事:

  1. \(A\)\(-B\) 的闵可夫斯基和 \(C\)
  2. 快速判断点是否在多边形内

第一件事我们已经知道了。
第二件事,我们可以把凸包 \(C\) 的任意一个端点当做原点 \(O\)\(\overrightarrow{OX}\) 在以 O 为原点、按照 atan2(逆时针)极角排序后的点集 \(C\) 中的后继 \(P\),以及 \(P\) 的前驱 \(Q\),利用 \(\overrightarrow{PX}\)\(\overrightarrow {PQ}\) 的顺逆时针关系判断。特判:\(O,P,X\) 三点共线时,先要在排序时让 \(OP>OQ\),然后判断 \(OX\) 是否 \(\le OP\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
	register char ch=getchar();register int x=0,f=1;
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x*f;
}
const int N=1e5+5;
const double eps=1e-9;
int n,m,q,num;
struct P {int x,y,vx,vy;double tht;double d(){return sqrt(1.0*x*x+1.0*y*y);}}a[N],b[N],e[N*2],c[N*2],tmp[N];
P operator-(P a,P b){return P{a.x-b.x,a.y-b.y};}
ll operator*(P a,P b){return 1ll*a.x*b.y-1ll*a.y*b.x;}
void Hull(int &n,P a[N]){
	sort(a+1,a+n+1,[](P a,P b){return a.x<b.x;});
	static int stk[N],hul[N*2];
	for(int i=1;i<=n;i++)tmp[i]=a[i];
	int tp=0,cnt=0;
	for(int i=1;i<=n;i++){
		while(tp>1&&(a[stk[tp]]-a[stk[tp-1]])*(a[i]-a[stk[tp]])<=0)tp--;
		stk[++tp]=i;
	}
	for(int i=1;i<=tp;i++)hul[++cnt]=stk[i];
	tp=0;
	for(int i=n;i;i--){
		while(tp>1&&(a[stk[tp]]-a[stk[tp-1]])*(a[i]-a[stk[tp]])<=0)tp--;
		stk[++tp]=i;
	}
	for(int i=1;i<=tp;i++)hul[++cnt]=stk[i];
	sort(hul+1,hul+cnt+1),cnt=unique(hul+1,hul+cnt+1)-hul-1;
	n=cnt;
	for(int i=2;i<=cnt;i++)a[i]=tmp[hul[i]],a[i].tht=atan2(a[i].y-a[1].y,a[i].x-a[1].x);
	sort(a+2,a+n+1,[](P a,P b){return a.tht<b.tht;});
}
bool fl;
bool inpoly(P a,int n,P b[N]){
	if(a.tht<b[1].tht||a.tht>b[n].tht)return 0;
	if(abs(a.tht-b[n].tht)<eps)return a.d()<=b[n].d();
	int L=0,R=n+1,mid;
	while(L<R-1){
		mid=L+R>>1;
		if(b[mid].tht>eps+a.tht)R=mid;
		else L=mid;
	}//cout<<b[R-1].x<<' '<<b[R-1].y<<'\n'<<b[R].x<<' '<<b[R].y<<'\n'<<a.x<<' '<<a.y<<'\n';
	return (a-b[R])*(b[R-1]-b[R])>=0;
}
int main(){
	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();
	Hull(n,a),Hull(m,b);
	a[0]=a[n],b[0]=b[m];
	for(int i=1;i<=n;i++)
		e[++num]=P{0,0,a[i].x-a[i-1].x,a[i].y-a[i-1].y,atan2(a[i].y-a[i-1].y,a[i].x-a[i-1].x)};
	for(int i=1;i<=m;i++)
		e[++num]=P{0,0,b[i].x-b[i-1].x,b[i].y-b[i-1].y,atan2(b[i].y-b[i-1].y,b[i].x-b[i-1].x)};
	sort(e+1,e+num+1,[](P a,P b){return a.tht<b.tht;});
	int mnax=2e9,mnbx=2e9,mnay=2e9,mnby=2e9,mncx=2e9,mncy=2e9;
	for(int i=1;i<=n;i++)mnax=min(mnax,a[i].x),mnay=min(mnay,a[i].y);
	for(int i=1;i<=m;i++)mnbx=min(mnbx,b[i].x),mnby=min(mnby,b[i].y);
	P poi=P{0,0};
	for(int i=1;i<=num;i++)c[i]=P{poi.x,poi.y,0,0,atan2(poi.y,poi.x)},poi.x+=e[i].vx,poi.y+=e[i].vy;
	sort(c+1,c+num+1,[](P a,P b){return abs(a.tht-b.tht)<eps?a.d()<b.d():a.tht<b.tht;});
	//for(int i=1;i<=n;i++)cout<<a[i].x<<' '<<a[i].y<<'\n';
	for(int i=1;i<=num;i++)mncx=min(mncx,c[i].x),mncy=min(mncy,c[i].y);
	//printf("%d %d %d %d %d %d\n",mnax,mnay,mnbx,mnby,mncx,mncy);
	for(int i=1,x,y;i<=q;i++){
		x=read()+mncx-mnax-mnbx,y=read()+mncy-mnay-mnby;
		//if(i==62720)cerr<<x<<' '<<y<<'\n',fl=1;
		//cout<<x<<' '<<y<<'\n';
		cout<<inpoly(P{x,y,0,0,atan2(y,x)},num,c)<<'\n';//if(i==62720)fl=0;
	}
}
posted @ 2022-07-27 22:02  pengyule  阅读(464)  评论(0编辑  收藏  举报