codeforces 70D 动态凸包

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

两种操作

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

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


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

比如,用水平序求凸包的时候,会有两条凸线,一条上凸折线,一条下凸折线,那么判断一个点在这个凸包内就是判断这个点是否在上凸折线的下方以及是否在下凸折线的上方codeforces 70D 动态凸包_第1张图片


如上图所示是一条下凸折线,新增点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;
}


你可能感兴趣的:(codeforces 70D 动态凸包)