CF70D Professor's task
阿新 • • 發佈:2022-01-17
兩種操作:
- 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\) 的判斷。
程式碼:
本部落格作者:Werner_Yin(https://www.cnblogs.com/werner-yin/) ,轉載時請註明出處,謝謝支援!#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; }