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

众所周知,三角形的重心坐标是\((\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. HashSet去重

    class Program     {         static void Main(string[] args)         {             Console.WriteLine( ...

  2. Kafka学习笔记之Kafka自身操作日志的清理方法(非Topic数据)

    0x00 概述 本文主要讲Kafka自身操作日志的清理方法(非Topic数据),Topic数据自己有对应的删除策略,请看这里. Kafka长时间运行过程中,在kafka/logs目录下产生了大量的ka ...

  3. Java自学-类和对象 类方法

    Java的类方法和对象方法 类方法: 又叫做静态方法 对象方法: 又叫实例方法,非静态方法 访问一个对象方法,必须建立在有一个对象的前提的基础上 访问类方法,不需要对象的存在,直接就访问 步骤 1 : ...

  4. Django---ORM的常用字段和自定义字段,DjangoORM字段与数据库类型对应,字段参数和Meta的参数,Django的admin操作,13中orm操作方法,单标的双下方法

    Django---ORM的常用字段和自定义字段,DjangoORM字段与数据库类型对应,字段参数和Meta的参数,Django的admin操作,13中orm操作方法,单标的双下方法 一丶ORM常用字段 ...

  5. UIDatePicker基本使用

    UIDatePicker提供了一个快速选择日期和时间的控件,他是UIControl的子类,专门用于日期时间的选择.其样式可以通过UIDatePicker的属性进行灵活设置,同时也可以获取到当前UIDa ...

  6. Nexus6p手机root和安装xposed

    进行root前需要两个前提条件 解锁OEM 进入开发者选项:设置-〉关于-〉一直点版本号会出现,usb调试打开 手机连接pc命令行输入: adb reboot bootloader 进入bootloa ...

  7. WDA演练一:用户登陆界面设计(一)

    一,新建用户表: 用户和密码参考标准的.这里给用户分了几个维度,以便后面进行接下来的业务设定. 二,新建ZLY_PORTAL 程序. 除了MAIN视图外,在添加LOGON视图. 1.导入预先做好的主页 ...

  8. Java面试通关要点 汇总集【最终版】

    本文转载自公众号:服务端思维,阅读大约需要7分钟.梁兄的知识储备很丰富,组织的知识星球里也是干货十足,平常还会有技术研习等活动,欢迎关注. 首先,声明下,以下知识点并非阿里的面试题.这里,笔者结合自己 ...

  9. Linux装B命令

    原文:https://mp.weixin.qq.com/s/CNmMRjl0iZ8EBPq5VgJHsA 1.空心字体 yum install -y figlet figlet happy 1.0 2 ...

  10. php+js实现极验,拖动滑块验证码验证表单

    现在很多网站,比如淘宝,京东等都改用使用极验拖动验证码实现登录,这种方式比传统的验证码方式有更好的体验,减少用户输入的错误,也同样能起到防盗刷的功能.现在很多极验都是第三方的,也很多都是收费的.今天在 ...