codeforces 70D 动态凸包

http://www.codeforces.com/problemset/problem/70/D

两种操作

1:增加一个点,会形成一个新的凸包

2:判断某个点是否在凸包内


有两种方法可以做,不过都类似的,都是根据求凸包的方法来做的。

比如,用水平序求凸包的时候,会有两条凸线,一条上凸折线,一条下凸折线,那么判断一个点在这个凸包内就是判断这个点是否在上凸折线的下方以及是否在下凸折线的上方


如上图所示是一条下凸折线,新增点now在折线的下方,即在凸包外部,所以要找到水平序相邻的两个点p x,然后左边从p开始,利用叉积判断不断的删点,右边类似。。最后两条红色的线就是新的凸包的边,p q x 由于now这个点的加入而被删除了。

加入一个点的时候,我们需要找到凸线上水平序相邻的两个点,然后向两边不停的删点,直到满足凸包的定义为止

找到相邻的两个点可以用平衡树,用stl的话会简便很多很多。

注:一个小细节,传参数的时候没加引用,直接TLE了

#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
typedef pair<int, int> pii;
typedef long long lld;
#define MP make_pair
#define X first
#define Y second
map<int, int> Convex[2];
map<int, int>::iterator p , it , it1 , it2 ,q;
lld cross(pii a, pii b, pii c) {
	return (lld) (b.X - a.X) *(c.Y - a.Y) - (lld) (b.Y - a.Y) *(c.X - a.X);
}
bool judge(map<int, int> &st, int x, int y) {
	if (!st.size())    return false;
	if (st.find(x) != st.end())  return y >= st[x];
	if (x < st.begin()->X || (--st.end())->X < x)   return false;
	p = st.lower_bound(x);
	q = p;  q --;
	return cross(MP(x, y), *q, *p) >= 0;
}
void insert(map<int, int> &st, int x, int y) {
	if (judge(st, x, y))   return; 
	st[x] = y;
	p = st.upper_bound(x);
	it1 = it2 = it = p; it-- ; 
	it1 = it;  it1--;  it2 = it1; it2--;
	if(p != st.end() ){
	    q = p; q++;
		while(q != st.end() && cross(MP(x,y),*q,*p) >= 0)	{
			st.erase(p);	p = q;	q ++;
		}
	}
	if(it == st.begin() || it1 == st.begin()) return ;
	while(it1 != st.begin() && cross(MP(x,y),*it1,*it2) >= 0){
		st.erase(it1);  it1 = it2 ;  	it2 --;
	}
}
int main() {
	int Q, op, x, y;
	scanf("%d", &Q);
	while (Q--) {
		scanf("%d%d%d", &op, &x, &y);
		if (op == 1) {
			insert(Convex[0], x, y);
			insert(Convex[1], x, -y);
		} else {
			bool ans1 = judge(Convex[0], x, y) ;
			bool ans2 = judge(Convex[1], x, -y);
			if (ans1 && ans2)
				puts("YES");
			else
				puts("NO");
		}
	}
	return 0;
}


  • 21
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

haha593572013

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值