20200908 专题:动态凸包

总览:

以一个点为基准点,用角度维护凸包
插入一个点时,找到前驱后继,分别弹一下
可以用 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值