CF70D Professor's task


两种操作:

  • 1 往点集 S 中添加一个点 \((x, y)\)
  • 2 询问 \((x,y)\) 是否在点集 S 的凸包中。
    数据保证至少有一个 \(2\) 操作,保证刚开始会给出三个 \(1\) 操作, 且这三个操作中的点不共线。

\(n \le 10^5\)


  计算几何 凸包 平衡树

  动态凸包板子题目,考虑正常的凸包维护方式:

  • \(\text{x-y}\) 排序,优先 \(x\) 坐标小的,然后再是 \(y\) 坐标小的。
  • 使用单调栈维护上凸壳、下凸壳(根据叉积判断)。

  对于这个题目,我们可以使用平衡树维护 \(\text{x-y}\) 排序的结果,每次插入的时候判断是否已经在凸包里面,然后再模拟单调栈进行弹栈。

  具体实现的时候可以拿两个 struct 分别维护上下凸壳,通过 template 传参来判断不同的条件减少代码量,但是要注意几个细节:

  • \(x\) 相同的时候,凸包上面只能留一个点。
  • 注意 template 传参后叉积为 \(0\) 的判断。

  代码:

#include 

#define in read()

using namespace std;

using ll = long long;

const int N = 1e5 + 10;
const int inf = 1e9;

struct vect {
	int x, y;
	vect (int _x = 0, int _y = 0) : x(_x), y(_y) { }
	bool friend operator < (vect a, vect b) { return a.x ^ b.x ? a.x < b.x : a.y < b.y; }
	vect friend operator - (vect a, vect b) { return vect(a.x - b.x, a.y - b.y); }
	ll friend operator ^ (vect a, vect b) { return 1ll * a.x * b.y - 1ll * a.y * b.x; }
};

template < int N, bool op > struct convex_hull { // op = 0 : 上凸壳, op = 1 : 下凸壳
	set < vect > al;
	bool valid(vect a, vect b, vect c) { // in the convex hull
		ll res = (a - b) ^ (c - b);
		return (res == 0) || ((res < 0) ^ op);
	}
	bool check(vect x) { // in the convex hull
		auto it = al.lower_bound(vect(x.x, -inf)); if(it == al.end()) return false;
		if((*it).x == x.x) return (*it).y == x.y || (((*it).y > x.y) ^ op);
		if(it != al.begin()) return valid(*prev(it), x, *it); return false;
	}
	bool remove(set < vect > :: iterator it) {
		if(it == al.begin() || next(it) == al.end()) return false;
		if(valid(*prev(it), *it, *next(it))) return al.erase(it), true;
		return false;
	}
	void insert(vect x) {
		if(check(x)) return; auto it = al.lower_bound(vect(x.x, -inf)); 
                if(it != al.end() && (*it).x == x.x) al.erase(it);
		al.insert(x); it = al.find(x);
		if(it != al.begin()) { it--; while(remove(it++)) it--; }
		if(++it != al.end()) { while(remove(it--)) it++; }
	}
};

convex_hull < N, 0 > up;
convex_hull < N, 1 > down;

int main() {
	int Q = in;
	while(Q--) {
		int op = in, x = in, y = in; vect t(x, y);
		if(op == 1) up.insert(t), down.insert(t);
		else puts(up.check(t) && down.check(t) ? "YES" : "NO");
	}
	return 0;
}