【题意】
维护一个凸包,支持:
1、向凸包内新加入一个点;
2、询问某个点是否在当前凸包中。
【题解】
平时求凸包的时候,要用上极角排序。
那么,就排序吧。
然而,极点应该在哪里呢?
考虑到开头保证能给出一个没有退化的三角形,那么,就用这个三角形的重心作为极点。为了避免精度误差,就不除以
3
3
3了,改为将所有点的坐标乘
3
3
3。由于不求面积什么的,所以后面的操作就跟未乘
3
3
3的时候一样。
接下来先想如何判断点是否在凸包内。
考虑到如下情形(阴影部分为凸包):
显然,凸包上面的顶点均满足:
a
1
<
a
2
<
.
.
.
<
a
n
(
a
表
示
极
点
序
序
号
)
a_1<a_2<...<a_n(a表示极点序序号)
a1<a2<...<an(a表示极点序序号)
而且,若将这个点塞到凸包中,它的极点序序号也满足这个式子。所以,我们将点的前驱与后继求出来,然后用向量的叉积判断这个新加入点的凹凸性即可。
插入点的时候,先判断这个点是否在凸包内(因为如果在凸包内,这个点对原凸包是没有贡献的),然后把这个点插入这个凸包。
接着,找出这个点的前驱的前驱,判断凹凸性,一直往前面判断,直到找到一个凸点为止。后继也是一样的道理。
至于找前驱后继,可以用set/手写平衡树来搞。时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
注意:可能有这种情况(标号为极角序序号,当前凸包中有m个顶点):
此时只需特判即可。
然而,计算几何说起来是一套一套的,写起来就是二楞二楞的了TAT,写了差不多半天才写出来。
【代码】
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#define it set<point> :: iterator
using namespace std;
const double eps = 1e-7;
double ox, oy;
inline int dcmp(double x)
{
if(fabs(x) < eps)
return 0;
return x < 0 ? -1 : 1;
}
struct point{
double x, y, ang;
point(){}
point(double a, double b) : x(a), y(b) {ang = atan2(y - oy, x - ox);}
point operator -(const point a) const{return point(x - a.x, y - a.y);}
bool operator <(const point a) const {return dcmp(ang - a.ang) == 0 ? dcmp((x - ox) * (x - ox) - (a.x - ox) * (a.x - ox) + (y - oy) * (y - oy) - (a.y - oy) * (a.y - oy)) < 0 : dcmp(ang - a.ang) < 0;}
bool operator ==(const point a)const{return dcmp(ang - a.ang) == 0 && dcmp((x - ox) * (x - ox) - (a.x - ox) * (a.x - ox) + (y - oy) * (y - oy) - (a.y - oy) * (a.y - oy)) == 0;}
}p[5];
set<point > s;
inline double cross(point a, point b) {return a.x * b.y - a.y * b.x;}
inline it l(it x) {
if(x == s.begin()) x = s.end();
x--;
return x;
}
inline it r(it x) {
x++;
if(x == s.end()) x = s.begin();
return x;
}
inline bool check_inside(point p)
{
if(s.size() < 3)
return 0;
it a, b = s.lower_bound(p);
if(b == s.end())
b = s.begin();
a = l(b);
return dcmp(cross(p - *a, *b - p)) <= 0;
}
inline void push(point p)
{
if(check_inside(p))
return;
s.insert(p);
it pos = s.find(p), b = l(pos), a = l(b);
while(dcmp(cross(*b - *a, p - *b)) <= 0)
s.erase(b), b = a, a = l(a);
a = r(pos), b = r(a);
while(dcmp(cross(*a - p, *b - *a)) <= 0)
s.erase(a), a = b, b = r(b);
}
int main()
{
int n, t;
double a, b;
scanf("%d", &n);
for(int i = 0; i < 3; i++)
{
scanf("%d%lf%lf", &t, &p[i].x, &p[i].y);
ox += p[i].x, oy += p[i].y;
p[i].x *= 3, p[i].y *= 3;
}
for(int i = 0; i < 3; i++)
p[i] = point(p[i].x, p[i].y), s.insert(p[i]);
n -= 3;
while(n--)
{
scanf("%d%lf%lf", &t, &a, &b), a *= 3, b *= 3;
if(t == 1)
push(point(a, b));
else
puts(check_inside(point(a, b)) ? "YES" : "NO");
}
}