Codeforces 70D Professor's task [动态凸包]

题意:初始给你三个点,之后有若干操作

①加入一个点,使点集成为一个新的凸包

②判断一个点是否在凸包中

题解:对点进行极角排序(用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");
		}
	} 
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值