Problem p00902 (C++) — buggy submission, verdict: Runtime Error

#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <utility>
#include <vector>
namespace lc {
static const double EPS = 1e-9;
inline double abs(double x) { return std::abs(x); }
inline bool tolerant_eq(double a, double b) { return abs(a - b) < EPS; }
} // namespace lc
namespace lc {
struct Point {
  double x;
  double y;
  explicit Point(const double &x = 0.0, const double &y = 0.0) : x(x), y(y) {}
  Point operator+(const Point &p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point &p) const { return Point(x - p.x, y - p.y); }
  Point operator*(const Point &p) const {
    return Point(x * p.x - y * p.y, x * p.y + y * p.x);
  }
  Point operator/(double s) const { return Point(x / s, y / s); }
  double abs() const { return sqrt(x * x + y * y); }
  double arg() const { return atan2(y, x); }
};
inline bool tolerant_eq(const Point &a, const Point &b) {
  return tolerant_eq(a.x, b.x) && tolerant_eq(a.y, b.y);
}
} // namespace lc
namespace lc {
struct Circle {
  Point c;
  double r;
  explicit Circle(const Point &c = Point(), double r = 0.0) : c(c), r(r) {}
};
inline bool tolerant_eq(const Circle &a, const Circle &b) {
  return tolerant_eq(a.c, b.c) && tolerant_eq(a.r, b.r);
}
} // namespace lc
namespace lc {
inline bool intersect(const Circle &a, const Circle &b) {
  const double d = (a.c - b.c).abs();
  return d <= a.r + b.r && a.r + d >= b.r && b.r + d >= a.r;
}
} // namespace lc
namespace lc {
inline std::vector<Point> crossing_points(const Circle &a, const Circle &b) {
  std::vector<Point> ret;
  if (!intersect(a, b)) {
    return ret;
  }
  if (tolerant_eq(a, b)) {
    ret.push_back(a.c + Point(a.r, 0.0));
    ret.push_back(a.c + Point(-a.r, 0.0));
    ret.push_back(a.c + Point(0.0, a.r));
  } else {
    const double d = (a.c - b.c).abs();
    const double rc = (d * d + a.r * a.r - b.r * b.r) / (2.0 * d);
    const double rs = sqrt(a.r * a.r - rc * rc);
    const Point diff = (b.c - a.c) / d;
    const Point x = a.c + diff * Point(rc, rs);
    const Point y = a.c + diff * Point(rc, -rs);
    ret.push_back(x);
    if (!tolerant_eq(x, y)) {
      ret.push_back(y);
    }
  }
  return ret;
}
} // namespace lc
using namespace std;
inline bool contains_all(const lc::Circle &c, const vector<lc::Circle> &cs) {
  for (const auto &t : cs) {
    const double d = (c.c - t.c).abs();
    if (d + t.r > c.r + lc::EPS) {
      return false;
    }
  }
  return true;
}
int main() {
  ios_base::sync_with_stdio(false);
  cout << setiosflags(ios::fixed) << setprecision(10);
  while (true) {
    int n;
    double r;
    cin >> n >> r;
    if (n == 0) {
      break;
    }
    std::vector<lc::Circle> circles(n);
    for (int i = 0; i < n; ++i) {
      cin >> circles[i].c.x >> circles[i].c.y >> circles[i].r;
    }
    vector<lc::Point> corners;
    vector<vector<double>> args(n);
    for (int i = 0; i < n; ++i) {
      for (int j = i + 1; j < n; ++j) {
        const lc::Circle a(circles[i].c, r - circles[i].r);
        const lc::Circle b(circles[j].c, r - circles[j].r);
        const auto cps = lc::crossing_points(a, b);
        for (const auto &p : cps) {
          if (contains_all(lc::Circle(p, r), circles)) {
            corners.push_back(p);
            args[i].push_back((p - a.c).arg());
            args[j].push_back((p - b.c).arg());
          }
        }
      }
    }
    int m = 0;
    for (const auto &p : corners) {
      bool accept = true;
      for (int i = 0; accept && i < m; ++i) {
        if (!lc::tolerant_eq(p, corners[i])) {
          continue;
        }
        accept = false;
      }
      if (accept) {
        corners[m++] = p;
      }
    }
    corners.resize(m);
    double answer = 0.0;
    if (m == 0) {
      for (const auto &c : circles) {
        if (!contains_all(c, circles)) {
          continue;
        }
        const double s = r * 2.0 - c.r;
        answer = s * 2.0 * M_PI;
        break;
      }
    } else if (m == 1) {
      const lc::Circle c(corners[0], r);
      if (contains_all(c, circles)) {
        answer = r * 2.0 * M_PI;
      }
    } else {
      double remains = 2.0 * M_PI;
      for (int i = 0; i < n; ++i) {
        sort(args[i].begin(), args[i].end());
        int k = 0;
        for (size_t j = 0; j < args[i].size(); ++j) {
          if (k == 0 || !lc::tolerant_eq(args[i][j], args[i][k - 1])) {
            args[i][k++] = args[i][j];
          }
        }
        args[i].resize(k);
        double sum = 0.0;
        for (size_t j = 0; j + 1 < args[i].size(); j += 2) {
          sum += args[i][j + 1] - args[i][j];
        }
        sum = min(sum, 2.0 * M_PI - sum);
        const double s = r * 2.0 - circles[i].r;
        answer += s * sum;
        remains -= sum;
      }
      answer += r * remains;
    }
    cout << answer << endl;
  }
  return 0;
}

Error: WA

Fixed submission:

#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <utility>
#include <vector>
namespace lc {
static const double EPS = 1e-9;
inline double abs(double x) { return std::abs(x); }
inline bool tolerant_eq(double a, double b) { return abs(a - b) < EPS; }
} // namespace lc
namespace lc {
struct Point {
  double x;
  double y;
  explicit Point(const double &x = 0.0, const double &y = 0.0) : x(x), y(y) {}
  Point operator+(const Point &p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point &p) const { return Point(x - p.x, y - p.y); }
  Point operator*(double s) const { return Point(x * s, y * s); }
  Point operator/(double s) const { return Point(x / s, y / s); }
  double abs() const { return sqrt(x * x + y * y); }
  Point unit() const { return *this / abs(); }
  Point ortho() const { return Point(-y, x); }
  double arg() const { return atan2(y, x); }
};
inline Point operator*(double s, const Point &p) { return p * s; }
inline bool tolerant_eq(const Point &a, const Point &b) {
  return tolerant_eq(a.x, b.x) && tolerant_eq(a.y, b.y);
}
inline double cross(const Point &a, const Point &b) {
  return a.x * b.y - a.y * b.x;
}
inline double dot(const Point &a, const Point &b) {
  return a.x * b.x + a.y * b.y;
}
inline int ccw(const Point &a, const Point &b, const Point &c) {
  Point d = b - a, e = c - a;
  if (cross(d, e) > 0.0) {
    return 1;
  }
  if (cross(d, e) < 0.0) {
    return -1;
  }
  if (dot(d, e) < 0.0) {
    return 2;
  }
  if (d.abs() < e.abs()) {
    return -2;
  }
  return 0;
}
} // namespace lc
namespace lc {
struct Circle {
  Point c;
  double r;
  explicit Circle(const Point &c = Point(), double r = 0.0) : c(c), r(r) {}
};
inline bool tolerant_eq(const Circle &a, const Circle &b) {
  return tolerant_eq(a.c, b.c) && tolerant_eq(a.r, b.r);
}
} // namespace lc
namespace lc {
inline bool intersect(const Circle &a, const Circle &b) {
  const double d = (a.c - b.c).abs();
  return d <= a.r + b.r && a.r + d >= b.r && b.r + d >= a.r;
}
} // namespace lc
namespace lc {
inline std::vector<Point> crossing_points(const Circle &a, const Circle &b) {
  std::vector<Point> ret;
  if (!intersect(a, b)) {
    return ret;
  }
  if (tolerant_eq(a, b)) {
    ret.push_back(a.c + Point(a.r, 0.0));
    ret.push_back(a.c + Point(-a.r, 0.0));
    ret.push_back(a.c + Point(0.0, a.r));
  } else {
    const double l = (b.c - a.c).abs();
    const double s = (l + a.r + b.r) / 2.0;
    const double S = sqrt(s * (s - l) * (s - a.r) * (s - b.r));
    const double d = (S * 2.0) / l;
    const double t = sqrt(a.r * a.r - d * d);
    const Point v = t * (b.c - a.c).unit();
    const Point w = d * v.ortho().unit();
    const Point x = a.c + v + w, y = a.c + v - w;
    ret.push_back(x);
    if (!tolerant_eq(x, y)) {
      ret.push_back(y);
    }
  }
  return ret;
}
} // namespace lc
using namespace std;
int main() {
  ios_base::sync_with_stdio(false);
  cout << setiosflags(ios::fixed) << setprecision(10);
  while (true) {
    int n;
    double r;
    cin >> n >> r;
    if (n == 0) {
      break;
    }
    std::vector<lc::Circle> circles(n);
    for (int i = 0; i < n; ++i) {
      cin >> circles[i].c.x >> circles[i].c.y >> circles[i].r;
    }
    bool finish = false, possible = false;
    double answer = 0.0;
    vector<lc::Point> corners;
    vector<vector<int>> io_flags;
    for (int i = 0; !finish && i < n; ++i) {
      bool contains_all = true;
      for (int j = 0; j < n; ++j) {
        if (i == j) {
          continue;
        }
        const double d = (circles[i].c - circles[j].c).abs();
        if (d + circles[j].r > circles[i].r + lc::EPS) {
          contains_all = false;
        }
      }
      if (contains_all) {
        possible = true;
      }
      for (int j = i + 1; j < n; ++j) {
        const lc::Circle a(circles[i].c, r - circles[i].r);
        const lc::Circle b(circles[j].c, r - circles[j].r);
        const auto cps = lc::crossing_points(a, b);
        if (cps.size() == 1) {
          answer = r * 2.0 * M_PI;
          finish = true;
          break;
        }
        for (const auto &p : cps) {
          bool accept = true;
          double limit = r * r + lc::EPS;
          for (const auto &q : circles) {
            const double d = (q.c - p).abs() + q.r;
            if (d * d > limit) {
              accept = false;
            }
          }
          if (!accept) {
            continue;
          }
          possible = true;
          int key = -1;
          for (size_t k = 0; key < 0 && k < corners.size(); ++k) {
            if (lc::tolerant_eq(corners[k], p)) {
              key = k;
            }
          }
          if (key < 0) {
            key = corners.size();
            corners.push_back(p);
            io_flags.push_back(vector<int>(n));
          }
          if (lc::ccw(a.c, p, b.c) == 1) {
            io_flags[key][i] |= 1;
            io_flags[key][j] |= 2;
          } else {
            io_flags[key][i] |= 2;
            io_flags[key][j] |= 1;
          }
        }
      }
    }
    if (finish || !possible) {
      cout << answer << endl;
      continue;
    }
    if (corners.empty()) {
      double max_r = 0.0;
      for (const auto &c : circles) {
        max_r = max(max_r, c.r);
      }
      answer = (r * 2.0 - max_r) * 2.0 * M_PI;
      cout << answer << endl;
      continue;
    }
    const int m = corners.size();
    vector<vector<double>> in_rads(n), out_rads(n);
    for (int i = 0; i < m; ++i) {
      const lc::Point &p = corners[i];
      for (int j = 0; j < n; ++j) {
        const lc::Circle &c = circles[j];
        if (io_flags[i][j] & 1) {
          in_rads[j].push_back((p - c.c).arg());
        }
        if (io_flags[i][j] & 2) {
          out_rads[j].push_back((p - c.c).arg());
          out_rads[j].push_back((p - c.c).arg() + 2.0 * M_PI);
          ;
        }
      }
    }
    double remains = 2.0 * M_PI;
    for (int i = 0; i < n; ++i) {
      if (in_rads[i].empty()) {
        continue;
      }
      sort(out_rads[i].begin(), out_rads[i].end());
      const double s = 2.0 * r - circles[i].r;
      for (const auto &in_r : in_rads[i]) {
        const auto out_r =
            *lower_bound(out_rads[i].begin(), out_rads[i].end(), in_r);
        remains -= (out_r - in_r);
        answer += s * (out_r - in_r);
      }
    }
    answer += remains * r;
    cout << answer << endl;
  }
  return 0;
}