题意:初始给你三个点,之后有若干操作
①加入一个点,使点集成为一个新的凸包
②判断一个点是否在凸包中
题解:对点进行极角排序(用set维护),判断点是否在凸包内时,查找该点的前驱和后继,判断叉积即可。对于加入的点的操作,我们需要将点插入set用判断凸包的方法,从该点出发,对其左右进行判断。
AC代码:
#include<stdio.h>
#include<set>
#include<math.h>
using namespace std;
typedef long long ll;
struct point
{
ll x,y;
ll len;
double ang;
point(){}
point(ll x,ll y)
{
this->x=x;
this->y=y;
}
}o,a[5];
ll q;
set<point>st;
set<point>::iterator qian,hou,it;
bool operator<(point a,point b)
{
if(a.ang==b.ang)return a.len<b.len;
return a.ang<b.ang;
}
point operator-(point A,point B) //点-点=向量
{
return point(A.x-B.x,A.y-B.y);
}
ll Cross(point A,point B) //叉积
{
return A.x*B.y-A.y*B.x;
}
set<point>::iterator L(set<point>::iterator x)
{
if(x == st.begin()) x = st.end();
x--;
return x;
}
set<point>::iterator R(set<point>::iterator x) {
x++;
if(x == st.end()) x = st.begin();
return x;
}
int main()
{
scanf("%lld",&q);
ll op;
for(ll i=0;i<3;i++)
{
scanf("%lld%lld%lld",&op,&a[i].x,&a[i].y);
o.x+=a[i].x;
o.y+=a[i].y;
a[i].x*=3;
a[i].y*=3;
}
for(ll i=0;i<3;i++)
{
a[i].len=(ll)(a[i].y-o.y)*(a[i].y-o.y)+(ll)(a[i].x-o.x)*(a[i].x-o.x);
a[i].ang=atan2(a[i].y-o.y,a[i].x-o.x);
st.insert(a[i]);
}
q-=3;
while(q--)
{
ll x,y;
scanf("%lld%lld%lld",&op,&x,&y);
x*=3,y*=3;
point p=point(x,y);
p.len=(ll)(y-o.y)*(y-o.y)+(ll)(x-o.x)*(x-o.x);
p.ang=atan2(y-o.y,x-o.x);
hou=st.lower_bound(p);
if(hou==st.end())hou=st.begin();
qian=L(hou);
if(op==1)
{
if(Cross(p-*qian,*hou-p)<=0)continue;
st.insert(p);
set<point>::iterator cur,i,j;
cur=st.find(p);
i=L(cur);j=L(i);
while(Cross(*j-*cur,*i-*j) <= 0) {
st.erase(i);
i=j;j=L(j);
}
i=R(cur);j=R(i);
while(Cross(*j-*cur,*i-*j) >= 0) {
st.erase(i);
i=j;j=R(i);
}
}
else
{
if(Cross(p-*qian,*hou-p)<=0)printf("YES\n");
else printf("NO\n");
}
}
}