[JSOI2018] 战争
作者:互联网
一、题目
二、解法
哈哈哈,这道题我都给草过去了,计算几何学懂啦\(\sim\)
发现部落的管辖范围就是求凸包,那么我们先把两个部落的凸包求出来。
任意取第一个凸包的一点 \(a\),第二个凸包的一点 \(b\),设位移向量是 \(d\),那么两个凸包管辖范围不交等价于向量 \(v=a-b-d\) 非零,发现 \(a-b\) 是一种闵可夫斯基和的形式,我们把第二个凸包的所有点取反,然后做闵可夫斯基和,问题变成了判断点 \(d\) 在不在合并后的凸包中。
可以 \(O(\log n)\) 快速判断,首先把凸包左下角的点平移到 \((0,0)\),凸包的所有边本身就是有极角顺序的,设 \(c_i\) 为凸包上第 \(i\) 个点,翻译成叉积就是 \(c_i\times c_{i+1}<0\),也就是第 \(i\) 个点到第 \(i+1\) 个点有一个顺时针转角。
首先判断边界情况,然后找到待判定顺时针方向上的第一个凸包上的点,做一下叉积就可以判断该点是否在凸包上了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
const int M = 200005;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,k,q;
struct point
{
int x,y;
point(int X=0,int Y=0) : x(X) , y(Y) {}
point operator + (point b) {return point(x+b.x,y+b.y);}
point operator - (point b) {return point(x-b.x,y-b.y);}
int operator * (point b) {return x*b.y-y*b.x;}
bool operator < (const point &b) const {
return x==b.x?y<b.y:x<b.x;
}
}a[M],b[M],c[M],v[M],s[M],t[M];
void conv(point *a,int &n)
{
int m=0;
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
while(m>1 && (a[i]-v[m-1])*(v[m]-v[m-1])<=0) m--;
v[++m]=a[i];
}
int tmp=m;
for(int i=n-1;i>=1;i--)
{
while(m>tmp && (a[i]-v[m-1])*(v[m]-v[m-1])<=0) m--;
v[++m]=a[i];
}
n=m-1;memcpy(a,v,sizeof v);
}
void merge()
{
for(int i=1;i<=n;i++) s[i]=a[i%n+1]-a[i];
for(int i=1;i<=m;i++) t[i]=b[i%m+1]-b[i];
int i=1,j=1;c[++k]=a[1]+b[1];
while(i<=n && j<=m) k++,c[k]=c[k-1]+(s[i]*t[j]<=0?s[i++]:t[j++]);
while(i<=n) k++,c[k]=c[k-1]+s[i++];
while(j<=m) k++,c[k]=c[k-1]+t[j++];
}
int cmp(point x,point y)
{
return x*y<0;
}
int ask(point x)
{
if(c[k]*x<0 || x*c[2]<0) return 0;
int p=lower_bound(c+1,c+1+k,x,cmp)-c-1;
return (x-c[p])*(c[p%k+1]-c[p])>=0;
}
signed 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();
conv(a,n);conv(b,m);
merge();
conv(c,k);point bs=c[1];
for(int i=1;i<=k;i++) c[i]=c[i]-bs;
while(q--)
{
int x=read(),y=read();
printf("%d\n",ask(point(x,y)-bs));
}
}
标签:战争,JSOI2018,凸包,int,while,read,&&,include 来源: https://www.cnblogs.com/C202044zxy/p/15112379.html