计算几何板子题(我才没有拷板子的说……)

众所周知,三角形的重心坐标是\((\frac{x_1+x_2+x_3}{3},\frac{y_1+y_2+y_3}{3})\)

然后我们发现如果我们有一个点集\(P=\{\vec a+\vec b+\vec c|\vec a\in A,\vec b \in B,\vec c\in C\}\),那么就可以直接查询\((3\times x_,3\times y)\)在不在这个点集里得到答案

其实这样的点集在计算几何上是有名字的,就是传说中的闵可夫斯基和

通俗地讲,点集\(A,B\)的闵可夫斯基和就是:从原点向\(A\)内部的每一个点做向量,将\(B\)沿每个向量移动,所有的最终位置的并

然后我们考虑凸包的闵可夫斯基和,手玩一下就会发现它的边是由原来凸包的边构成的

也就是说把两凸包的边极角排序后直接顺次连起来就是闵可夫斯基和,那么我们求的时候直接归并排序即可(凸包已经有序了)

所以这题就做完了,点在凸包内可以直接搞一个点作为原点,然后二分找极角最接近的边判断

坑点1:可能出现三点共线的情况,因此要扔回去再求一遍凸包

坑点2:极角排序的时候注意三点共线

坑点3:如果找到的极角最接近的边已经到最大的一条了,那么请考虑共线的情况

CODE

#include<cstdio>
#include<algorithm>
#define RI register LL
#define CI const LL&
using namespace std;
typedef long long LL;
const LL N=1000005;
struct Point
{
LL x,y;
inline Point(LL X=0,LL Y=0)
{
x=X; y=Y;
}
inline friend bool operator ==(const Point& A,const Point& B)
{
return A.x==B.x&&A.y==B.y;
}
}A[N],B[N],C[N],stack[N*3],t[N*3],p,st; LL n,m,k,q,num;
typedef Point Vector;
inline LL Cross(const Vector& A,const Vector& B)
{
return A.x*B.y-A.y*B.x;
}
inline LL Dot(const Vector& A,const Vector& B)
{
return A.x*B.x+A.y*B.y;
}
inline Point operator +(const Point& A,const Point& B)
{
return Point(A.x+B.x,A.y+B.y);
}
inline Vector operator -(const Point& A,const Point& B)
{
return Vector(A.x-B.x,A.y-B.y);
}
inline Point operator *(const Point& A,CI v)
{
return Point(A.x*v,A.y*v);
}
inline bool cmp(const Point& A,const Point& B)
{
return A.x<B.x||(A.x==B.x&&A.y<B.y);
}
inline bool Ang_cmp(const Vector& A,const Vector& B)
{
return Cross(A,B)>0||(!Cross(A,B)&&Dot(A,A)<Dot(B,B));
}
class Computation_Geometry
{
private:
Vector va[N],vb[N];
public:
inline LL ConvexHull(Point *a,int n)
{
sort(a+1,a+n+1,cmp); n=unique(a+1,a+n+1)-a-1;
RI i,top=0; for (i=1;i<=n;++i)
{
while (top>1&&Cross(stack[top]-stack[top-1],a[i]-stack[top])<=0) --top;
stack[++top]=a[i];
}
LL temp=top; for (i=n-1;i;--i)
{
while (top>temp&&Cross(stack[top]-stack[top-1],a[i]-stack[top])<=0) --top;
stack[++top]=a[i];
}
if (n>1) --top; for (i=1;i<=top;++i) a[i]=stack[i]; return a[top+1]=a[1],top;
}
inline LL Minkowski_Sum(Point *a,CI n,Point *b,CI m)
{
RI i,tot; for (i=1;i<n;++i) va[i]=a[i+1]-a[i]; va[n]=a[1]-a[n];
for (i=1;i<m;++i) vb[i]=b[i+1]-b[i]; vb[m]=b[1]-b[m]; t[tot=1]=a[1]+b[1];
RI pa=1,pb=1; while (pa<=n&&pb<=m) ++tot,t[tot]=t[tot-1]+(Cross(va[pa],vb[pb])>=0?va[pa++]:vb[pb++]);
while (pa<=n) ++tot,t[tot]=t[tot-1]+va[pa++]; while (pb<=m) ++tot,t[tot]=t[tot-1]+vb[pb++]; return tot;
}
inline bool IsPointInConvexHull(Point *a,CI n,const Point& p)
{
if (Cross(p,a[1])>0||Cross(a[n],p)>0) return 0;
LL pos=lower_bound(a+1,a+n+1,p,Ang_cmp)-t-1;
if (pos==n) return Dot(p,p)<=Dot(a[n],a[n]);
return Cross(p-a[pos],a[pos%n+1]-a[pos])<=0;
}
}G;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (scanf("%lld",&n),i=1;i<=n;++i) scanf("%lld%lld",&A[i].x,&A[i].y);
for (scanf("%lld",&m),i=1;i<=m;++i) scanf("%lld%lld",&B[i].x,&B[i].y);
for (scanf("%lld",&k),i=1;i<=k;++i) scanf("%lld%lld",&C[i].x,&C[i].y);
n=G.ConvexHull(A,n); m=G.ConvexHull(B,m); k=G.ConvexHull(C,k);
num=G.Minkowski_Sum(A,n,B,m); num=G.ConvexHull(t,num);
num=G.Minkowski_Sum(C,k,t,num); num=G.ConvexHull(t,num);
//for (i=1;i<=num;++i) printf("%lld %lld\n",t[i].x,t[i].y);
for (st=t[1],i=1;i<=num;++i) t[i]=t[i]-st; num=G.ConvexHull(t,num);
for (scanf("%lld",&q),i=1;i<=q;++i)
scanf("%lld%lld",&p.x,&p.y),puts(G.IsPointInConvexHull(t,num,(p*3)-st)?"YES":"NO");
return 0;
}

关于闵可夫斯基和,还有一道有关的题目(竟然老早就做掉了233):JSOI2018]战争 还需要一个小小的转换

HHHOJ #151. 「NOI模拟 #2」Nagisa的更多相关文章

  1. HHHOJ #153. 「NOI模拟 #2」Kotomi

    抽代的成分远远大于OI的成分 首先把一个点定为原点,然后我们发现如果我们不旋转此时答案就是所有位置的\(\gcd\) 如果要选择怎么办,我们考虑把我们选定的网格边连同方向和大小看做单位向量\(\vec ...

  2. Solution -「NOI 模拟赛」彩色挂饰

    \(\mathcal{Description}\)   给定一个含 \(n\) 个点 \(m\) 条边的简单无向图,设图中最大点双的大小为 \(s\),则保证 \(s\le6\).你将要用 \(k\) ...

  3. Solution -「NOI 模拟赛」出题人

    \(\mathcal{Description}\)   给定 \(\{a_n\}\),求一个 \(\{b_{n-1}\}\),使得 \(\forall x\in\{a_n\},\exists i,j\ ...

  4. 「CSP-S模拟赛」2019第四场

    「CSP-S模拟赛」2019第四场 T1 「JOI 2014 Final」JOI 徽章 题目 考场思考(正解) T2 「JOI 2015 Final」分蛋糕 2 题目 考场思考(正解) T3 「CQO ...

  5. 「NOI十联测」深邃

    「NOI十联测」深邃 要使得最大的连通块最小,显然先二分答案. 先固定1结点为根. 对于一个果实,显然是先处理子树中未分配的点,再向外延伸. 每个结点记录一个\(si[]\),表示子树中未分配的点数, ...

  6. 「NOI十联测」奥义商店

    「NOI十联测」奥义商店 若lzz想花费最少的钱,那么显然要选择数目较少的颜色. 先考虑暴力的写法. 每次向两边统计,每个物品要求被买的概率可以由上一个物品推出. now=1;//now 被买概率 M ...

  7. 「NOI十联测」黑暗

    「NOI十联测」黑暗 \(n\) 个点的无向图,每条边都可能存在,一个图的权值是连通块个数的 \(m\) 次方,求所有可能的图的权值和.(n≤30000,m≤15) 令\(ans[n][m]\)为n个 ...

  8. 「CSP-S模拟赛」2019第三场

    目录 T1 「POI2007」山峰和山谷 Ridges and Valleys 题目 考场思路(几近正解) 正解 T2 「JOI 2013 Final」 现代豪宅 题目 考场思路(正解) T3 「SC ...

  9. 【模拟】HHHOJ#251. 「NOIP模拟赛 伍」高精度

    积累模拟经验 题目描述 维护一个二进制数,支持如下操作 "+" 该数加 11 "-" 该数减 11 "*" 该数乘 22 "\&q ...

随机推荐

  1. C# 多维数组 交错数组的区别,即 [ , ] 与 [ ][ ]的区别 (转载)

    多维数组的声明 在声明时,必须指定数组的长度,格式为 type [lenght ,lenght ,lengh, ... ] , ]; 或声明时即赋值,由系统推断长度 int [,] test1 = { ...

  2. 使用docker部署titpetric/netdata

    netdata 是常用的Linux系统性能实时监控面板 官方docker netdata/netdata部署 docker run -d --name=netdata \ -p 19999:19999 ...

  3. C#里面如何判断一个Object是否是某种类型

    第一种方法 var isA = oldObject.GetType() == typeof(Dictionary<string, string>) 第二种方法 var isB = oldO ...

  4. Git 多人协作 以及推送分支

    参考链接:https://www.liaoxuefeng.com/wiki/896043488029600/900375748016320 当你从远程仓库克隆时,实际上Git自动把本地的仓库的mast ...

  5. Matlab代理模式

    代理模式(Proxy)就是给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用.代理模式和装饰模式非常类似,但最主要的区别是代理模式中,代理类对被代理的对象有控制权,决定其执行或者不执行.本 ...

  6. 《微信小程序项目开发实战:用WePY、mpvue、Taro打造高效的小程序》(笔记1)WePY开发环境的安装

    WePY的安装或更新都通过npm进行,全局安装或更新WePY命令行工具,使用以下命令: npm install wepy-cli -g 稍等片刻,成功安装后,即可创建WePY项目. 注意:如果npm安 ...

  7. mysqldump 备份

    1.  直接备份某个库或表 ,或多个库多个表mysqldump -uroot -pPassword [database name] > [dump file]mysqldump -uroot - ...

  8. 2015年br运维操作归档

    归档2015年在br做运维时常用的命令,主要梳理出log的过滤操作. 对于日志文本的处理,常见还是sed和awk,具体如下: 统计ip访问量: cat nginx.log |awk '{print $ ...

  9. python的异常种类

    AttributeError 访问一个对象没有的属性 比如:foo.x 但是foo没有x属性 IOError 输入/输出异常 基本是无法打开文件 ImportError 无法映入模块或包 路径或者名称 ...

  10. MySQL Execution Plan--将范围扫描转换为等值查询

    将大于或小于的范围查询装换为等值查询 在生产环境,经常会遇到需要对Worker表进行多次尝试的业务,超过一定重试次数后抛弃或使用其他方式处理,在查找满足重试条件数据时,通常会使用“小于”运算符并伴随排 ...