Problem p01562 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>

using namespace std;

const double EPS = 1e-4, PI = acos(-1), INF = 1e9;

inline bool eq(double a, double b) { return abs(b - a) < EPS; }

struct Point {
  double x, y;

  Point(){};

  Point(double x, double y) : x(x), y(y){};

  Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }

  Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }

  Point operator*(const double b) const { return Point(x * b, y * b); }

  Point operator*(const Point &b) const {
    return Point(x * b.x - y * b.y, x * b.y + y * b.x);
  }

  Point operator/(const double b) const { return Point(x / b, y / b); }

  bool operator<(const Point &b) const { return x != b.x ? x < b.x : y < b.y; }

  bool operator==(const Point &b) const { return eq(x, b.x) && eq(y, b.y); }

  double norm() const { return x * x + y * y; }

  double arg() { return atan2(x, y); }

  double abs() const { return sqrt(norm()); }

  Point rotate(double theta) {
    return Point(cos(theta) * x - sin(theta) * y,
                 sin(theta) * x + cos(theta) * y);
  }

  Point rotate90() { return Point(-y, x); }

  friend ostream &operator<<(ostream &os, Point &p) {
    return os << "(" << p.x << "," << p.y << ")";
  }

  friend istream &operator>>(istream &is, Point &a) { return is >> a.x >> a.y; }
};

double cross(const Point &a, const Point &b) { return a.x * b.y - a.y * b.x; }

double dot(const Point &a, const Point &b) { return a.x * b.x + a.y * b.y; }

int ccw(const Point &a, Point b, Point c) {
  b = b - a, c = c - a;
  if (cross(b, c) > EPS)
    return +1;
  if (cross(b, c) < -EPS)
    return -1;
  if (dot(b, c) < 0)
    return +2;
  if (b.norm() < c.norm())
    return -2;
  return 0;
}

struct Segment {
  Point a, b;

  Segment(){};

  Segment(Point a, Point b) : a(a), b(b){};

  friend ostream &operator<<(ostream &os, Segment &p) {
    return os << "(" << p.a.x << "," << p.a.y << ") to (" << p.b.x << ","
              << p.b.y << ")";
  }

  friend istream &operator>>(istream &is, Segment &a) {
    return is >> a.a.x >> a.a.y >> a.b.x >> a.b.y;
  }
};

typedef vector<Point> Polygon;

double Area2(const Polygon &p) {
  double A = 0;
  for (int i = 0; i < p.size(); ++i) {
    A += cross(p[i], p[(i + 1) % p.size()]);
  }
  return A;
}

bool Intersect(const Segment &s, const Point &p) {
  return ccw(s.a, s.b, p) == 0;
}

bool Intersect(const Segment &s, const Segment &t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
         ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

Point Crosspoint(const Segment &l, const Segment &m) {
  double A = cross(l.b - l.a, m.b - m.a);
  double B = cross(l.b - l.a, l.b - m.a);
  if (abs(A) < EPS && abs(B) < EPS)
    return m.a; // same line
  return m.a + (m.b - m.a) * B / A;
}

double GetAngle(const Point &a, const Point &b) {
  double tmp = min(1.0, max(-1.0, dot(a, b) / a.abs() / b.abs()));
  double r = acos(tmp) * 180.0 / PI;
  if (cross(a, b) < -EPS)
    r = 360 - r;
  return r;
}

bool merge_if_able(Segment &s1, Segment s2) {
  if (abs(cross(s1.b - s1.a, s2.b - s2.a)) > EPS)
    return false;
  if (ccw(s1.a, s2.a, s1.b) == 1 || ccw(s1.a, s2.a, s1.b) == -1)
    return false;
  if (ccw(s1.a, s1.b, s2.a) == -2 || ccw(s2.a, s2.b, s1.a) == -2)
    return false;
  s1 = Segment(min(s1.a, s2.a), max(s1.b, s2.b));
  return true;
}

void merge_segments(vector<Segment> &segs) {
  for (int i = 0; i < segs.size(); i++) {
    if (segs[i].b < segs[i].a)
      swap(segs[i].a, segs[i].b);
  }
  for (int i = 0; i < segs.size(); i++) {
    for (int j = i + 1; j < segs.size(); j++) {
      if (merge_if_able(segs[i], segs[j])) {
        segs[j--] = segs.back(), segs.pop_back();
      }
    }
  }
}

vector<vector<int>> SegmentArrangement(vector<Segment> &segs,
                                       vector<Point> &ps) {
  vector<vector<int>> g;
  const int N = (int)segs.size();
  for (int i = 0; i < N; i++) {
    ps.emplace_back(segs[i].a);
    ps.emplace_back(segs[i].b);
    for (int j = i + 1; j < N; j++) {
      const Point p1 = segs[i].b - segs[i].a;
      const Point p2 = segs[j].b - segs[j].a;
      if (cross(p1, p2) == 0)
        continue;
      if (Intersect(segs[i], segs[j])) {
        ps.emplace_back(Crosspoint(segs[i], segs[j]));
      }
    }
  }
  sort(begin(ps), end(ps));
  ps.erase(unique(begin(ps), end(ps)), end(ps));

  const int M = (int)ps.size();
  g.resize(M);
  for (int i = 0; i < N; i++) {
    vector<int> vec;
    for (int j = 0; j < M; j++) {
      if (Intersect(segs[i], ps[j])) {
        vec.emplace_back(j);
      }
    }
    for (int j = 1; j < vec.size(); j++) {
      g[vec[j - 1]].push_back(vec[j]);
      g[vec[j]].push_back(vec[j - 1]);
    }
  }
  return (g);
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N;
  cin >> N;
  vector<Segment> segs;

  {
    Point pv;
    for (int i = 0; i < N; i++) {
      Point curr;
      cin >> curr;
      if (i)
        segs.emplace_back((Segment){pv, curr});
      pv = curr;
    }
  }

  vector<Point> ps;
  merge_segments(segs);
  auto g = SegmentArrangement(segs, ps);

  Point s(INF, INF);
  int t;
  for (auto &p : ps)
    s = min(s, p);
  for (int i = 0; i < ps.size(); i++)
    if (ps[i] == s)
      t = i;

  Polygon poly;

  function<void(int, int)> dfs = [&](int idx, int par) {
    if (idx == t)
      return;
    pair<double, int> nxt(INF, -1);
    for (auto &to : g[idx]) {
      double arg = GetAngle(ps[par] - ps[idx], ps[to] - ps[idx]);
      if (to == par)
        arg = 361;
      nxt = min(nxt, make_pair(arg, to));
    }
    poly.emplace_back(ps[idx]);
    dfs(nxt.second, idx);
  };
  double ret = 0;
  for (auto &to : g[t]) {
    poly.push_back(s);
    dfs(to, t);
    ret += max(0.0, Area2(poly));
    poly.clear();
  }
  cout << fixed << setprecision(12) << ret * 0.5 << endl;
}

Fixed submission:
#include <bits/stdc++.h>

using namespace std;

const double EPS = 1e-5, PI = acos(-1), INF = 1e9;

inline bool eq(double a, double b) { return abs(b - a) < EPS; }

struct Point {
  double x, y;

  Point(){};

  Point(double x, double y) : x(x), y(y){};

  Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }

  Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }

  Point operator*(const double b) const { return Point(x * b, y * b); }

  Point operator*(const Point &b) const {
    return Point(x * b.x - y * b.y, x * b.y + y * b.x);
  }

  Point operator/(const double b) const { return Point(x / b, y / b); }

  bool operator<(const Point &b) const { return x != b.x ? x < b.x : y < b.y; }

  bool operator==(const Point &b) const { return eq(x, b.x) && eq(y, b.y); }

  double norm() const { return x * x + y * y; }

  double arg() { return atan2(x, y); }

  double abs() const { return sqrt(norm()); }

  Point rotate(double theta) {
    return Point(cos(theta) * x - sin(theta) * y,
                 sin(theta) * x + cos(theta) * y);
  }

  Point rotate90() { return Point(-y, x); }

  friend ostream &operator<<(ostream &os, Point &p) {
    return os << "(" << p.x << "," << p.y << ")";
  }

  friend istream &operator>>(istream &is, Point &a) { return is >> a.x >> a.y; }
};

double cross(const Point &a, const Point &b) { return a.x * b.y - a.y * b.x; }

double dot(const Point &a, const Point &b) { return a.x * b.x + a.y * b.y; }

int ccw(const Point &a, Point b, Point c) {
  b = b - a, c = c - a;
  if (cross(b, c) > EPS)
    return +1;
  if (cross(b, c) < -EPS)
    return -1;
  if (dot(b, c) < 0)
    return +2;
  if (b.norm() < c.norm())
    return -2;
  return 0;
}

struct Segment {
  Point a, b;

  Segment(){};

  Segment(Point a, Point b) : a(a), b(b){};

  friend ostream &operator<<(ostream &os, Segment &p) {
    return os << "(" << p.a.x << "," << p.a.y << ") to (" << p.b.x << ","
              << p.b.y << ")";
  }

  friend istream &operator>>(istream &is, Segment &a) {
    return is >> a.a.x >> a.a.y >> a.b.x >> a.b.y;
  }
};

typedef vector<Point> Polygon;

double Area2(const Polygon &p) {
  double A = 0;
  for (int i = 0; i < p.size(); ++i) {
    A += cross(p[i], p[(i + 1) % p.size()]);
  }
  return A;
}

bool Intersect(const Segment &s, const Point &p) {
  return ccw(s.a, s.b, p) == 0;
}

bool Intersect(const Segment &s, const Segment &t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
         ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

Point Crosspoint(const Segment &l, const Segment &m) {
  double A = cross(l.b - l.a, m.b - m.a);
  double B = cross(l.b - l.a, l.b - m.a);
  if (abs(A) < EPS && abs(B) < EPS)
    return m.a; // same line
  return m.a + (m.b - m.a) * B / A;
}

double GetAngle(const Point &a, const Point &b) {
  double tmp = min(1.0, max(-1.0, dot(a, b) / a.abs() / b.abs()));
  double r = acos(tmp) * 180.0 / PI;
  if (cross(a, b) < -EPS)
    r = 360 - r;
  return r;
}

bool merge_if_able(Segment &s1, Segment s2) {
  if (abs(cross(s1.b - s1.a, s2.b - s2.a)) > EPS)
    return false;
  if (ccw(s1.a, s2.a, s1.b) == 1 || ccw(s1.a, s2.a, s1.b) == -1)
    return false;
  if (ccw(s1.a, s1.b, s2.a) == -2 || ccw(s2.a, s2.b, s1.a) == -2)
    return false;
  s1 = Segment(min(s1.a, s2.a), max(s1.b, s2.b));
  return true;
}

void merge_segments(vector<Segment> &segs) {
  for (int i = 0; i < segs.size(); i++) {
    if (segs[i].b < segs[i].a)
      swap(segs[i].a, segs[i].b);
  }
  for (int i = 0; i < segs.size(); i++) {
    for (int j = i + 1; j < segs.size(); j++) {
      if (merge_if_able(segs[i], segs[j])) {
        segs[j--] = segs.back(), segs.pop_back();
      }
    }
  }
}

vector<vector<int>> SegmentArrangement(vector<Segment> &segs,
                                       vector<Point> &ps) {
  vector<vector<int>> g;
  const int N = (int)segs.size();
  for (int i = 0; i < N; i++) {
    ps.emplace_back(segs[i].a);
    ps.emplace_back(segs[i].b);
    for (int j = i + 1; j < N; j++) {
      const Point p1 = segs[i].b - segs[i].a;
      const Point p2 = segs[j].b - segs[j].a;
      if (cross(p1, p2) == 0)
        continue;
      if (Intersect(segs[i], segs[j])) {
        ps.emplace_back(Crosspoint(segs[i], segs[j]));
      }
    }
  }
  sort(begin(ps), end(ps));
  ps.erase(unique(begin(ps), end(ps)), end(ps));

  const int M = (int)ps.size();
  g.resize(M);
  for (int i = 0; i < N; i++) {
    vector<int> vec;
    for (int j = 0; j < M; j++) {
      if (Intersect(segs[i], ps[j])) {
        vec.emplace_back(j);
      }
    }
    for (int j = 1; j < vec.size(); j++) {
      g[vec[j - 1]].push_back(vec[j]);
      g[vec[j]].push_back(vec[j - 1]);
    }
  }
  return (g);
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N;
  cin >> N;
  vector<Segment> segs;

  {
    Point pv;
    for (int i = 0; i < N; i++) {
      Point curr;
      cin >> curr;
      if (i)
        segs.emplace_back((Segment){pv, curr});
      pv = curr;
    }
  }

  vector<Point> ps;
  merge_segments(segs);
  auto g = SegmentArrangement(segs, ps);

  Point s(INF, INF);
  int t;
  for (auto &p : ps)
    s = min(s, p);
  for (int i = 0; i < ps.size(); i++)
    if (ps[i] == s)
      t = i;

  Polygon poly;

  function<void(int, int)> dfs = [&](int idx, int par) {
    if (idx == t)
      return;
    pair<double, int> nxt(INF, -1);
    for (auto &to : g[idx]) {
      double arg = GetAngle(ps[par] - ps[idx], ps[to] - ps[idx]);
      if (to == par)
        arg = 361;
      nxt = min(nxt, make_pair(arg, to));
    }
    poly.emplace_back(ps[idx]);
    dfs(nxt.second, idx);
  };
  double ret = 0;
  for (auto &to : g[t]) {
    poly.push_back(s);
    dfs(to, t);
    ret += max(0.0, Area2(poly));
    poly.clear();
  }
  cout << fixed << setprecision(12) << ret * 0.5 << endl;
}