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

众所周知,三角形的重心坐标是\((\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. 华为 S5700 交换机 批量修改端口方法

    常常在配置交换机端口的时候需要将多个端口设置为相同的配置,当时各端口逐一去配置不仅慢,而且容易出错,这个时候就需要对端口进行批量设置,不仅快捷,而且避免了反复输出容易出错的情况.不同系列.不同版本交换 ...

  2. 关于.net core 中的signalR组件的使用

    SignalR是为了提供更方便的web交互响应式到推送式的解决方案.有了它之后可以实现客户端直接调用服务端的方法并且获得返回值 (客户端可以是各种平台,目前SignalR支持的语言版本有C#.java ...

  3. 关于VS2019使用Git时遇到的Bug

    最近在运行vs2017时老是卡死,神烦!迫于无奈我从微软官网下载了vs2019,安装后打开项目,发现从git上拉取代码时报错如下: Please make sure you have the corr ...

  4. C#读写修改设置调整UVC摄像头画面-伽玛

    有时,我们需要在C#代码中对摄像头的伽玛进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像 ...

  5. 什么是MVC框架?

    1.什么是mvc Model View Controller,是模型-视图-控制器的缩写,一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到一个组件里,在改进和个性化 ...

  6. Java深入学习(2):并发队列

    并发队列: 在并发队列中,JDK有两套实现: ConcurrentLinkedQueue:非阻塞式队列 BlockingQueue:阻塞式队列 阻塞式队列非阻塞式队列的区别: 阻塞式队列入列操作的时候 ...

  7. linux系统crontab

    一.cron 简介 在LINUX中,周期执行的任务一般由cron这个守护进程来处理[ps -ef|grep cron].cron读取一个或多个配置文件,这些配置文件中包含了命令行及其调用时间. cro ...

  8. Nginx学习(一)

    Nginx I/O模型 网络I/O 本质是socket读取 第一步:将数据从磁盘文件先加载至内核内存空间(暖冲区),等待数据准备完成,时间较长. 第二部:将数据从内核缓冲区复制到用户空间的进程的内存中 ...

  9. SpringBoot2.x应用启动、关闭shell脚本

    本篇主要说明以下内容: 1.SpringBoot2.x应用启动.关闭的shell脚本 1 启动脚本 直接放到同jar包同一个目录下,如下: #!/usr/bin/env bash APPLICATIO ...

  10. Django 之 CBV

    Django 中有两种编写方式,FBV 和 CBV,那么什么是 FBV,CBV 又是什么呢? 一.什么是 CBV FBV(function base views) 就是在视图里使用函数处理请求(常见) ...