1. 程式人生 > 其它 >CF70D Professor's task

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 <bits/stdc++.h>

#define in read<int>()

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;
}
本部落格作者:Werner_Yin(https://www.cnblogs.com/werner-yin/) ,轉載時請註明出處,謝謝支援!