总览:
以一个点为基准点,用角度维护凸包
插入一个点时,找到前驱后继,分别弹一下
可以用 set 维护
因为基准点在中间,所以用叉积判断方向时要先判象限
T1 #1249. SGU277 HERO 动态凸包
思路:
板子题
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
typedef unsigned long long ull;
typedef unsigned int uint;
#define pb push_back
#define mp make_pair
#define int long long
namespace IO {
char buf_[1 << 21], *p1_ = buf_, *p2_ = buf_;
#define ch() \
(p1_ == p2_ && \
(p2_ = (p1_ = buf_) + fread(buf_, 1, 1 << 21, stdin), p1_ == p2_) \
? EOF \
: *p1_++)
inline int in() {
int s = 0, f = 1;
char x = ch();
for (; x < '0' || x > '9'; x = ch())
if (x == '-') f = -1;
for (; x >= '0' && x <= '9'; x = ch()) s = (s * 10) + (x & 15);
return f == 1 ? s : -s;
}
char _buf[1 << 21];
int _p1 = -1;
inline void flush() {
fwrite(_buf, 1, _p1 + 1, stdout);
_p1 = -1;
}
inline void pc(char x) {
if (_p1 == (1 << 21) - 1) flush();
_buf[++_p1] = x;
}
inline void out(int x) {
char k[30];
int pos = 0;
if (!x) {
pc('0');
return;
}
if (x < 0) {
pc('-');
x = -x;
}
while (x) {
k[++pos] = (x % 10) | 48;
x /= 10;
}
for (int i = pos; i; i--) pc(k[i]);
return;
}
inline void out(string x) {
int len = x.size();
for (int i = 0; i < len; i++) pc(x[i]);
}
} // namespace IO
using namespace IO;
const int A = 1e5 + 5;
const double EPS = 1e-15;
inline int cp(double u, double v) {
if (fabs(u - v) < EPS) return 0;
return u > v ? 1 : -1;
}
int n;
struct Point {
double x, y;
Point(double u = 0, double v = 0) { x = u, y = v; }
inline friend Point operator+(Point u, Point v) {
return Point(u.x + v.x, u.y + v.y);
}
inline friend Point operator-(Point u, Point v) {
return Point(u.x - v.x, u.y - v.y);
}
inline friend Point operator*(Point u, double v) {
return Point(u.x * v, u.y * v);
}
inline friend Point operator/(Point u, double v) {
return Point(u.x / v, u.y / v);
}
inline friend double operator^(Point u, Point v) {
return u.x * v.y - u.y * v.x;
}
inline friend double operator&(Point u, Point v) {
return u.x * v.x + u.y * v.y;
}
inline friend bool operator==(Point u, Point v) {
return !cp(u.x, v.x) && !cp(u.y, v.y);
}
inline friend bool operator!=(Point u, Point v) { return !(u == v); }
} a, b, c, base;
inline double dis(Point u, Point v) {
return sqrt((u.x - v.x) * (u.x - v.x) + (u.y - v.y) * (u.y - v.y));
}
inline bool operator<(Point u, Point v) {
Point uu = u - base, vv = v - base;
if (cp(uu.y * vv.y, 0) == -1) return uu.y < vv.y;
if (!cp(uu.y, 0) && !cp(vv.y, 0) && cp(uu.x * vv.x, 0) == -1)
return uu.x > vv.x;
if (cp(uu ^ vv, 0)) return cp(uu ^ vv, 0) == 1;
return cp(dis(u, base), dis(v, base)) == 1;
}
inline int area(Point u, Point v) {
Point uu = u - c, vv = v - c;
return abs((LL)uu.x * (LL)vv.y - (LL)uu.y * (LL)vv.x);
}
set<Point> t;
typedef set<Point>::iterator iter;
inline Point pre(Point u) {
iter it = t.find(u);
if (it == t.begin()) it = t.end();
it--;
return (*it);
}
inline Point suf(Point u) {
iter it = t.find(u);
it++;
if (it == t.end()) it = t.begin();
return (*it);
}
inline void del(Point u) {
iter it = t.find(u);
t.erase(it);
return;
}
int ans;
signed main() {
a.x = in(), a.y = in();
b.x = in(), b.y = in();
c.x = in(), c.y = in();
base = (a + b + c) / 3;
t.insert(a), t.insert(b), t.insert(c);
ans += area(a, b);
int num = 3;
n = in();
while (n--) {
a.x = in(), a.y = in();
if (t.find(a) != t.end()) {
out(ans), pc('\n');
continue;
}
t.insert(a);
Point u = pre(a), v = suf(a);
if (cp((u - a) ^ (v - a), 0) == 1) {
del(a);
out(ans), pc('\n');
continue;
}
num++;
ans -= area(u, v);
Point d = pre(u);
while (num > 3 && cp((a - d) ^ (u - d), 0) != -1) {
num--;
del(u);
ans -= area(u, d);
u = d;
d = pre(u);
}
d = suf(v);
while (num > 3 && cp((v - d) ^ (a - d), 0) != -1) {
num--;
del(v);
ans -= area(v, d);
v = d;
d = suf(v);
}
ans += area(u, a), ans += area(a, v);
out(ans), pc('\n');
}
flush();
return 0;
}