ABC251G

提供一个本质相同,但是不需要会向量也能做,而且很好想的方法。

首先发现凸包点少,也就意味着边少,考虑从边的方向寻找突破口。

考虑一个凸包的本质:若干个直线划分出若干个半平面,它们的交即为这个凸包。如果一个点对于每一条直线,都在于凸包的同侧,那么这个点就在这个凸包内。

这样直接暴力做仍然是 O(nmq) 的。但是明显发现每条直线相当于限制了,经过一个点 (x,y),斜率为 k 的直线的截距不小于/大于某个数。取其中最大/小的一个限制即可。O(nm) 预处理出来,O(nq) 解决。

要注意的是,这种写法细节比较多。平行于坐标轴的情况建议全部特判,test 5 极度卡精度,可以手写分数类解决。

比向量解法相对复杂,但是也很好写。

code:

点击查看代码
int n,m,q,a[N],b[N],op[N];
const double eps=1e-8;
struct frac{
	ll a,b;
	frac(ll _a=0,ll _b=1){
		a=_a,b=_b;
		if(b<0)a=-a,b=-b;
	}
	il bool operator<=(const frac &tmp)const{
		return (__int128)a*tmp.b<=(__int128)tmp.a*b;
	}
	il bool operator<(const frac &tmp)const{
		return (__int128)a*tmp.b<(__int128)tmp.a*b;
	}
	il frac operator-(const frac &tmp)const{
		return frac(a*tmp.b-b*tmp.a,b*tmp.b);
	}
	il frac operator*(const frac &tmp)const{
		return frac(a*tmp.a,b*tmp.b);
	}
}f[N],sl[N];
void check(int i,int j){
	if(a[i]==a[j]){
		if(b[i]<b[j])op[i]=2;
		else op[i]=4;
	}else if(b[i]==b[j]){
		if(a[i]>a[j])op[i]=3;
		else op[i]=5;
	}else{
		sl[i]=frac(b[i]-b[j],a[i]-a[j]);
		if(a[i]<a[j])op[i]=0;
		else op[i]=1;
	}
}
void Yorushika(){
	scanf("%d",&n);
	rep(i,1,n){
		scanf("%d%d",&a[i],&b[i]);
		if(i==1)
			continue;
		check(i,i-1);
	}
	check(1,n);
	rep(i,1,n){
		if(op[i]>=1&&op[i]<=3)f[i]=frac(-1ll*inf*inf,1);
		else f[i]=frac(1ll*inf*inf,1);
	}
	scanf("%d",&m);
	rep(j,1,m){
		int x,y;
		scanf("%d%d",&x,&y);
		rep(i,1,n){
			frac nx=frac(x+a[i],1),ny=frac(y+b[i],1);
			if(op[i]==0)f[i]=min(f[i],ny-nx*sl[i]);
			else if(op[i]==1)f[i]=max(f[i],ny-nx*sl[i]);
			else if(op[i]==2)f[i]=max(f[i],nx);
			else if(op[i]==3)f[i]=max(f[i],ny);
			else if(op[i]==4)f[i]=min(f[i],nx);
			else f[i]=min(f[i],ny);
		}
	}
	scanf("%d",&q);
	rep(j,1,q){
		frac x,y;
		scanf("%lld%lld",&x.a,&y.a);
		bool flag=true;
		rep(i,1,n){
			if(op[i]==0)flag&=y-x*sl[i]<=f[i];
			else if(op[i]==1)flag&=f[i]<=y-x*sl[i];
			else if(op[i]==2)flag&=f[i]<=x;
			else if(op[i]==3)flag&=f[i]<=y;
			else if(op[i]==4)flag&=x<=f[i];
			else flag&=y<=f[i];
		}
		if(flag)
			puts("Yes");
		else 
			puts("No");
	}
}
signed main(){
	int t=1;
	//	scanf("%d",&t);
	while(t--)
		Yorushika();
}

题外话:

zlt 怎么又做过?zlt 怎么又做过?zlt 怎么又做过?

posted @   yinhee  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示