ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[JSOI2018] 战争

2021-08-07 17:00:53  阅读:190  来源: 互联网

标签:战争 JSOI2018 凸包 int while read && include


一、题目

点此看题

二、解法

哈哈哈,这道题我都给草过去了,计算几何学懂啦\(\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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有