• [JSOI2018] 战争


    一、题目

    点此看题

    二、解法

    哈哈哈,这道题我都给草过去了,计算几何学懂啦(sim)

    发现部落的管辖范围就是求凸包,那么我们先把两个部落的凸包求出来。

    任意取第一个凸包的一点 (a),第二个凸包的一点 (b),设位移向量是 (d),那么两个凸包管辖范围不交等价于向量 (v=a-b-d) 非零,发现 (a-b) 是一种闵可夫斯基和的形式,我们把第二个凸包的所有点取反,然后做闵可夫斯基和,问题变成了判断点 (d) 在不在合并后的凸包中。

    可以 (O(log n)) 快速判断,首先把凸包左下角的点平移到 ((0,0)),凸包的所有边本身就是有极角顺序的,设 (c_i) 为凸包上第 (i) 个点,翻译成叉积就是 (c_i imes 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
    ",ask(point(x,y)-bs));
    	}
    }
    
  • 相关阅读:
    eslint 验证vue文件 报错 unexpected token =解决方法
    启动3ds Max报 d3dx9_43.dll丢失 解决方法
    windows下webpack不是内部命令 解决方法
    修改node.js默认的npm安装目录
    tp5 重定向缺少index.php报错(No input file specified)
    PHP单表操作mysqli数据库类的封装
    php 常见图片处理函数封装
    php图像处理函数image_type_to_extension、image_type_to_mime_type 的区别
    kubernetes集群部署mysql 8.0
    Maven ResourceBundle.getBundle读取Properties异常MissingResourceException: Can't find bundlei解决方法
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15112379.html
Copyright © 2020-2023  润新知