1. 程式人生 > 實用技巧 >題解 戰爭

題解 戰爭

題目傳送門

題目大意

給出兩個凸包\(A,B\),對於一個向量求出是否能通過按此向量移動其中一個凸包使得兩個凸包沒有交集。

凸包大小、查詢次數\(\le 10^5\)

思路

其實是個閔可夫斯基和的板題。

我們發現如果對於該向量\(\vec{x}\),存在\(a\in A,b\in B\)滿足\(a+\vec{x}=b\)那麼,顯然兩個凸包就會有交集。於是,判斷一個向量\(\vec{x}\)是否合法的方法就出來了,我們可以判斷是否存在\(a\in A,b\in B\)使得\(\vec{x}=a-b\)。然後我們發現如果我們設\(C\)\(A,(-B)\)的閔可夫斯基和的凸包,那麼,答案就是\(\vec{x}\)

是否在\(C\)中。

至於如何求出閔可夫斯基和以及如何判斷一個向量是否在一個凸包之中,可以看看xzyxzy的部落格

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define int long long
#define MAXN 100005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

struct Vector{
	int x,y;
	int len (){return x * x + y * y;}
	int operator * (const Vector &p)const{return x * p.y - y * p.x;}
	Vector operator + (const Vector &p)const{return Vector {x + p.x,y + p.y};}
	Vector operator - (const Vector &p)const{return Vector {x - p.x,y - p.y};}
};

bool cmp1 (Vector a,Vector b){return a.y < b.y || (a.y == b.y && a.x < b.x);}
bool cmp2 (Vector a,Vector b){return a * b > 0 || (a * b == 0 && a.len () < b.len());}

int tot,top,sta[MAXN];

void Convex (Vector *A,int &n){
	sort (A + 1,A + n + 1,cmp1);
	Vector st = A[1];for (Int i = 1;i <= n;++ i) A[i] = A[i] - st;
	sort (A + 2,A + n + 1,cmp2),sta[top = 1] = 1;
	for (Int i = 2;i <= n;sta[++ top] = i,++ i) while (top > 1 && (A[i] - A[sta[top - 1]]) * (A[sta[top]] - A[sta[top - 1]]) >= 0) -- top;
	for (Int i = 1;i <= top;++ i) A[i] = A[sta[i]] + st;
	n = top,A[n + 1] = A[1];
}

int n,m,q;
Vector s1[MAXN],s2[MAXN],A[MAXN],C1[MAXN],C2[MAXN];

void Minkowski (){
	for (Int i = 1;i < n;++ i) s1[i] = C1[i + 1] - C1[i];s1[n] = C1[1] - C1[n];
	for (Int i = 1;i < m;++ i) s2[i] = C2[i + 1] - C2[i];s2[m] = C2[1] - C2[m];
	A[tot = 1] = C1[1] + C2[1];int st1 = 1,st2 = 1;
	while (st1 <= n && st2 <= m) ++ tot,A[tot] = A[tot - 1] + (s1[st1] * s2[st2] >= 0 ? s1[st1 ++] : s2[st2 ++]);
	while (st1 <= n) ++ tot,A[tot] = A[tot - 1] + s1[st1 ++];
	while (st2 <= m) ++ tot,A[tot] = A[tot - 1] + s2[st2 ++];
}

bool Inside (Vector a){
	if (a * A[1] > 0 || A[tot] * a > 0) return 0;
	int pos = lower_bound (A + 1,A + tot + 1,a,cmp2) - A - 1;
	return (a - A[pos]) * (A[pos % tot + 1] - A[pos]) <= 0;
}

signed main(){
	read (n,m,q);
	for (Int i = 1;i <= n;++ i) read (C1[i].x,C1[i].y);Convex (C1,n);
	for (Int i = 1;i <= m;++ i) read (C2[i].x,C2[i].y),C2[i].x = -C2[i].x,C2[i].y = -C2[i].y;Convex (C2,m);
	Minkowski (),Convex (A,tot);Vector st = A[1];for (Int i = 1;i <= tot;++ i) A[i] = A[i] - st;
	for (Int i = 1;i <= q;++ i){
		Vector que;read (que.x,que.y);
		write (Inside (que - st)),putchar ('\n');
	}
	return 0;
}