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

#define _USE_MATH_DEFINES
#define _CRT_SECURE_NO_DEPRECATE

#include <algorithm>
#include <cassert>
#include <cfloat>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>

using namespace std;
const int MOD = 1000000009; // check!!!
const int INF = 100000000;  // 1e8

typedef long long ll;
typedef pair<int, int> Pii;
typedef pair<ll, ll> Pll;

#define FOR(i, n) for (int i = 0; i < (n); i++)
#define sz(c) ((int)(c).size())
#define ten(x) ((int)1e##x)
#define tenll(x) ((ll)1e##x)

const double EPS(1e-8);
const double PI = acos(-1.0);

#pragma region 基本要素(struct, typedef)

template <class T> struct point {
  T x, y;
  point() : x(0), y(0) {}
  point(const T &x, const T &y) : x(x), y(y) {}
  point operator+(const point &a) const { return point(x + a.x, y + a.y); }
  point &operator+=(const point &a) {
    x += a.x;
    y += a.y;
    return *this;
  }
  point operator-(const point &a) const { return point(x - a.x, y - a.y); }
  point &operator-=(const point &a) {
    x -= a.x;
    y -= a.y;
    return *this;
  }
  point operator*(const double a) const { return point(a * x, a * y); }
  point &operator*=(const double a) {
    x *= a;
    y *= a;
    return *this;
  }
  point operator/(const double a) const { return point(x / a, y / a); }
  point &operator/=(const double a) {
    x /= a;
    y /= a;
    return *this;
  }

  // 比較用
  bool operator<(const point &a) const {
    return (x != a.x) ? (x < a.x) : (y < a.y);
  }
};

template <class T> struct segment {
  point<T> a, b;
  segment() : a(point<T>()), b(point<T>()) {}
  segment(const point<T> &a, const point<T> &b) : a(a), b(b) {}
};

template <class T> struct line {
  point<T> a, b;
  line() : a(point<T>()), b(point<T>()) {}
  line(const point<T> &a, const point<T> &b) : a(a), b(b) {}
};

template <class T> struct circle {
  point<T> c;
  T r;
  circle() {}
  circle(const point<T> &c, T &r) : c(c), r(r) {}
};

typedef point<double> P;
typedef segment<double> S;
typedef line<double> L;
typedef circle<double> C;

#pragma endregion

#pragma region 基本要素(関数)

template <class T> T SQ(T x) { return x * x; }
template <class T> T dist2(const point<T> &a, const point<T> &b) {
  return SQ(a.x - b.x) + SQ(a.y - b.y);
}
template <class T> T abs2(const point<T> &p) { return SQ(p.x) + SQ(p.y); }
template <class T> T abs(const point<T> &p) { return sqrt(abs2(p)); }
template <class T> T dot(const point<T> &a, const point<T> &b) {
  return a.x * b.x + a.y * b.y;
}
template <class T> T cross(const point<T> &a, const point<T> &b) {
  return a.x * b.y - a.y * b.x;
}
template <class T> point<T> rot(const point<T> &a, const double theta) {
  return point<T>(a.x * cos(theta) - a.y * sin(theta),
                  a.x * sin(theta) + a.y * cos(theta));
}
template <class T> double arg(const point<T> &a) {
  double t = atan2(a.y, a.x);
  return t < 0 ? t + 2 * PI : t;
}

enum { CCW = 1, CW = -1, ON = 0 };
template <class T> int ccw(const point<T> &a, point<T> b, point<T> c) {
  b -= a;
  c -= a;
  double rdir = cross(b, c);
  double len =
      abs(b) * abs(c); // 誤差対策 (速度がやばい時は外すか、二乗に置き換える)
  if (rdir > EPS * len)
    return CCW; // cがabより上(反時計周り)
  if (rdir < -EPS * len)
    return CW; // cがabより下(時計周り)
  return ON;   // a,b,cが一直線上
}

#pragma endregion

#pragma region 入出力

std::ostream &operator<<(std::ostream &os, const P &point) {
  return (os << '(' << point.x << ',' << point.y << ')');
}
std::ostream &operator<<(std::ostream &os, const S &seg) {
  return (os << '{' << seg.a << ',' << seg.b << '}');
}
std::istream &operator>>(std::istream &is, P &point) {
  return (is >> point.x >> point.y);
}

#pragma endregion

// 交点が存在するかどうか
bool intersected(const S &S1, const S &S2) {
  if (max(S1.a.x, S1.b.x) + EPS < min(S2.a.x, S2.b.x) ||
      max(S1.a.y, S1.b.y) + EPS < min(S2.a.y, S2.b.y) ||
      max(S2.a.x, S2.b.x) + EPS < min(S1.a.x, S1.b.x) ||
      max(S2.a.y, S2.b.y) + EPS < min(S1.a.y, S1.b.y))
    return false;
  return ccw(S1.a, S1.b, S2.a) * ccw(S1.a, S1.b, S2.b) <= 0 &&
         ccw(S2.a, S2.b, S1.a) * ccw(S2.a, S2.b, S1.b) <= 0;
}

#pragma region 距離

// 線分と点の距離(2乗)
double dist2(const S &S, const P &p) {
  if (dot(S.b - S.a, p - S.a) <= 0)
    return dist2(p, S.a);
  if (dot(S.a - S.b, p - S.b) <= 0)
    return dist2(p, S.b);
  return (double)SQ(cross(S.b - S.a, p - S.a)) / dist2(S.a, S.b);
}

// 線分と点の距離
double dist(const S &S, const P &p) { return sqrt(dist2(S, p)); }

// 線分と線分の距離
double dist(const S &S1, const S &S2) {
  if (intersected(S1, S2))
    return 0;
  return sqrt(min(min(dist2(S1, S2.a), dist2(S1, S2.b)),
                  min(dist2(S2, S1.a), dist2(S2, S1.b))));
}

// 直線と点の距離
double dist(const L &L, const P &p) {
  return sqrt((double)SQ(cross(L.b - L.a, p - L.a)) / dist2(L.a, L.b));
}

// a -- bの間の円が入った時の、a - b間の距離
// 円の間に
double geodist(P a, P b, const C &c) {
  double r = c.r;
  S s(a, b);
  if (dist(s, c.c) > r)
    return abs(a - b);

  a -= c.c;
  b -= c.c;

  double L1 = abs(a);
  double t1 = arg(a) + acos(r / L1);
  if (t1 < 0)
    t1 += 2 * PI;
  double t2 = arg(a) - acos(r / L1);
  if (t2 < 0)
    t2 += 2 * PI;

  double L2 = abs(b);
  double t3 = arg(b) + acos(r / L2);
  if (t3 < 0)
    t3 += 2 * PI;
  double t4 = arg(b) - acos(r / L2);
  if (t4 < 0)
    t4 += 2 * PI;

  double theta = 2 * PI;
  theta = min(theta, min(abs(t1 - t4), 2 * PI - abs(t1 - t4)));
  theta = min(theta, min(abs(t2 - t3), 2 * PI - abs(t2 - t3)));
  return sqrt(L1 * L1 - r * r) + sqrt(L2 * L2 - r * r) + r * theta;
}

#pragma endregion

#pragma region 面積

// 多角形の面積
double area(const vector<P> &v) {
  double ans = 0;
  for (int i = 2; i < (int)v.size(); i++) {
    ans += cross(v[i - 1] - v[0], v[i] - v[0]);
  }
  return abs(ans) / 2;
}

// 三角形の面積
double area(const P &a, const P &b, const P &c) {
  return abs(cross(b - a, c - a)) / 2;
}

#pragma endregion

#pragma region 包含

// 凸包
vector<P> convex_hull(vector<P> &ps) {
  int n = ps.size(), k = 0;
  sort(ps.begin(), ps.end());
  vector<P> ch(2 * n);
  for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull
    while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;

  for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]) // upper-hull
    while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;

  ch.resize(k - 1);

  return ch;
}

// 三角形abcにpが含まれているかどうか(線上の場合も含む)
bool cover(const P &a, const P &b, const P &c, const P &p) {
  return area(a, b, c) + EPS >= area(a, b, p) + area(a, c, p) + area(b, c, p);
}

#pragma endregion

#pragma region 交点

// 円同士の交点
int intersect(const C &C1, const C &C2, P *p = NULL, P *q = NULL) {
  double r1 = C1.r, r2 = C2.r;
  P p1 = C1.c, p2 = C2.c;

  double d = abs(p1 - p2);
  if (d < EPS && abs(r1 - r2) < EPS) { // C1==C2
    return -1;
  } else if (r1 + r2 < d - EPS || d + EPS < abs(r1 - r2)) {
    return 0;
  } else {
    double a = (r1 * r1 - r2 * r2 + d * d) / (2 * d);
    double h = sqrt(max(r1 * r1 - a * a, 0.0));
    P tmp1 = p1 + (p2 - p1) * a / d;
    P tmp2 = (p2 - p1) * h / d;
    if (abs(tmp2) < EPS) {
      if (p && q)
        *p = *q = tmp1;
      return 1;
    } else {
      if (p && q) {
        *p = P(tmp1.x - tmp2.y, tmp1.y + tmp2.x);
        *q = P(tmp1.x + tmp2.y, tmp1.y - tmp2.x);
      }
      return 2;
    }
  }
}

// l : ax+by+c=0 に変換
inline void calc_abc(const L &l, double &a, double &b, double &c) {
  a = l.a.y - l.b.y;
  b = l.b.x - l.a.x;
  c = l.a.x * l.b.y - l.b.x * l.a.y;
}

// PからLへの垂線の足
P perp_foot(const P &p, const L &l) {
  double a, b, c;
  calc_abc(l, a, b, c);
  return p - P(a, b) * ((a * p.x + b * p.y + c) / (a * a + b * b));
}

// 円と直線の交点
int intersect(const C &c, const L &l, P *p = NULL, P *q = NULL) {
  P m = perp_foot(c.c, l);
  double d2 = abs2(c.c - m);
  if (c.r * c.r + EPS < d2)
    return 0;
  else if (abs(c.r * c.r - d2) < EPS) {
    if (p && q)
      *p = *q = m;
    return 1;
  } else {
    if (p && q) {
      P v;
      double n0 = abs2(l.a - m), n1 = abs2(l.b - m);
      if (n0 < n1)
        v = l.b - m, n0 = n1;
      else
        v = l.a - m;
      v *= sqrt((c.r * c.r - d2) / n0);
      *p = m + v, *q = m - v;
    }
    return 2;
  }
}

// 円と線分の交点
int intersect(const C &c, const S &s, P *p = NULL, P *q = NULL) {
  P pp, qq;
  int n = intersect(c, L(s.a, s.b), &pp, &qq);
  if (n == 0)
    return 0;
  else if (n == 1) {
    if (dot(pp - s.a, pp - s.b) < EPS) {
      if (p && q)
        *p = *q = pp;
      return 1;
    }
    return 0;
  } else {
    bool bp = (dot(pp - s.a, pp - s.b) < EPS);
    bool bq = (dot(qq - s.a, qq - s.b) < EPS);
    if (bp && bq) {
      if (p && q)
        *p = pp, *q = qq;
      return 2;
    }
    if (bp || bq) {
      if (p && q)
        *p = (bp ? pp : qq);
      return 1;
    }
    return 0;
  }
}

// 直線の交点
P intersect(const L &L1, const L &L2) {
  double a1 = cross(L1.b - L1.a, L2.b - L2.a);
  double a2 = cross(L1.b - L1.a, L1.b - L2.a);
  if (abs(a1) < EPS)
    return L1.a;
  return L2.a + (L2.b - L2.a) * (a2 / a1);
}

#pragma endregion

class CMP {
  C c;

public:
  CMP(const C &c) : c(c) {}
  bool operator()(const P &p, const P &q) const {
    double parg = arg(p - c.c);
    double qarg = arg(q - c.c);
    return parg < qarg;
  }
};

int main() {
  int n;
  while (cin >> n, n) {
    vector<C> vc(n);
    FOR(i, n) cin >> vc[i].c >> vc[i].r;

    double ans = 0;

    FOR(i, n) {
      vector<P> vp;
      FOR(j, n) if (i != j) {
        P p, q;
        int a = intersect(vc[i], vc[j], &p, &q);
        if (a == 1)
          vp.push_back(p);
        else if (a == 2)
          vp.push_back(p), vp.push_back(q);
      }

      sort(vp.begin(), vp.end(), CMP(vc[i]));

      ans += 2 * PI * vc[i].r;

      double dbg = 0;

      if (sz(vp) >= 2) {
        FOR(j, sz(vp)) {
          P &p = vp[j], &q = vp[(j + 1) % sz(vp)];
          double parg = arg(p - vc[i].c);
          double qarg = arg(q - vc[i].c);
          double dist, md;
          if (qarg < parg)
            dist = (qarg - parg + 2 * PI);
          else
            dist = qarg - parg;
          md = parg + dist / 2;

          P a(cos(md), sin(md));
          a = a * vc[i].r + vc[i].c;

          bool covered = false;
          FOR(k, n) if (i != k) {
            if (abs2(a - vc[k].c) < SQ(vc[k].r)) {
              covered = true;
            }
          }

          if (covered) {
            ans -= dist * vc[i].r;
          }

          dbg += dist;
        }
      } else {
        const double dist = 2 * PI;
        P a(vc[i].c.x + vc[i].r, vc[i].c.y);
        bool covered = false;
        FOR(k, n) if (i != k) {
          if (abs2(a - vc[k].c) < SQ(vc[k].r)) {
            covered = true;
          }
        }

        if (covered) {
          ans -= dist * vc[i].r;
        }
      }

      // assert(abs(dbg - 2*PI) < EPS);
    }

    printf("%.12f\\n", ans);
  }

  return 0;
}

Error: 0

Fixed submission:

#define _USE_MATH_DEFINES
#define _CRT_SECURE_NO_DEPRECATE

#include <algorithm>
#include <cassert>
#include <cfloat>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>

using namespace std;
const int MOD = 1000000009; // check!!!
const int INF = 100000000;  // 1e8

typedef long long ll;
typedef pair<int, int> Pii;
typedef pair<ll, ll> Pll;

#define FOR(i, n) for (int i = 0; i < (n); i++)
#define sz(c) ((int)(c).size())
#define ten(x) ((int)1e##x)
#define tenll(x) ((ll)1e##x)

const double EPS(1e-8);
const double PI = acos(-1.0);

#pragma region 基本要素(struct, typedef)

template <class T> struct point {
  T x, y;
  point() : x(0), y(0) {}
  point(const T &x, const T &y) : x(x), y(y) {}
  point operator+(const point &a) const { return point(x + a.x, y + a.y); }
  point &operator+=(const point &a) {
    x += a.x;
    y += a.y;
    return *this;
  }
  point operator-(const point &a) const { return point(x - a.x, y - a.y); }
  point &operator-=(const point &a) {
    x -= a.x;
    y -= a.y;
    return *this;
  }
  point operator*(const double a) const { return point(a * x, a * y); }
  point &operator*=(const double a) {
    x *= a;
    y *= a;
    return *this;
  }
  point operator/(const double a) const { return point(x / a, y / a); }
  point &operator/=(const double a) {
    x /= a;
    y /= a;
    return *this;
  }

  // 比較用
  bool operator<(const point &a) const {
    return (x != a.x) ? (x < a.x) : (y < a.y);
  }
};

template <class T> struct segment {
  point<T> a, b;
  segment() : a(point<T>()), b(point<T>()) {}
  segment(const point<T> &a, const point<T> &b) : a(a), b(b) {}
};

template <class T> struct line {
  point<T> a, b;
  line() : a(point<T>()), b(point<T>()) {}
  line(const point<T> &a, const point<T> &b) : a(a), b(b) {}
};

template <class T> struct circle {
  point<T> c;
  T r;
  circle() {}
  circle(const point<T> &c, T &r) : c(c), r(r) {}
};

typedef point<double> P;
typedef segment<double> S;
typedef line<double> L;
typedef circle<double> C;

#pragma endregion

#pragma region 基本要素(関数)

template <class T> T SQ(T x) { return x * x; }
template <class T> T dist2(const point<T> &a, const point<T> &b) {
  return SQ(a.x - b.x) + SQ(a.y - b.y);
}
template <class T> T abs2(const point<T> &p) { return SQ(p.x) + SQ(p.y); }
template <class T> T abs(const point<T> &p) { return sqrt(abs2(p)); }
template <class T> T dot(const point<T> &a, const point<T> &b) {
  return a.x * b.x + a.y * b.y;
}
template <class T> T cross(const point<T> &a, const point<T> &b) {
  return a.x * b.y - a.y * b.x;
}
template <class T> point<T> rot(const point<T> &a, const double theta) {
  return point<T>(a.x * cos(theta) - a.y * sin(theta),
                  a.x * sin(theta) + a.y * cos(theta));
}
template <class T> double arg(const point<T> &a) {
  double t = atan2(a.y, a.x);
  return t < 0 ? t + 2 * PI : t;
}

enum { CCW = 1, CW = -1, ON = 0 };
template <class T> int ccw(const point<T> &a, point<T> b, point<T> c) {
  b -= a;
  c -= a;
  double rdir = cross(b, c);
  double len =
      abs(b) * abs(c); // 誤差対策 (速度がやばい時は外すか、二乗に置き換える)
  if (rdir > EPS * len)
    return CCW; // cがabより上(反時計周り)
  if (rdir < -EPS * len)
    return CW; // cがabより下(時計周り)
  return ON;   // a,b,cが一直線上
}

#pragma endregion

#pragma region 入出力

std::ostream &operator<<(std::ostream &os, const P &point) {
  return (os << '(' << point.x << ',' << point.y << ')');
}
std::ostream &operator<<(std::ostream &os, const S &seg) {
  return (os << '{' << seg.a << ',' << seg.b << '}');
}
std::istream &operator>>(std::istream &is, P &point) {
  return (is >> point.x >> point.y);
}

#pragma endregion

// 交点が存在するかどうか
bool intersected(const S &S1, const S &S2) {
  if (max(S1.a.x, S1.b.x) + EPS < min(S2.a.x, S2.b.x) ||
      max(S1.a.y, S1.b.y) + EPS < min(S2.a.y, S2.b.y) ||
      max(S2.a.x, S2.b.x) + EPS < min(S1.a.x, S1.b.x) ||
      max(S2.a.y, S2.b.y) + EPS < min(S1.a.y, S1.b.y))
    return false;
  return ccw(S1.a, S1.b, S2.a) * ccw(S1.a, S1.b, S2.b) <= 0 &&
         ccw(S2.a, S2.b, S1.a) * ccw(S2.a, S2.b, S1.b) <= 0;
}

#pragma region 距離

// 線分と点の距離(2乗)
double dist2(const S &S, const P &p) {
  if (dot(S.b - S.a, p - S.a) <= 0)
    return dist2(p, S.a);
  if (dot(S.a - S.b, p - S.b) <= 0)
    return dist2(p, S.b);
  return (double)SQ(cross(S.b - S.a, p - S.a)) / dist2(S.a, S.b);
}

// 線分と点の距離
double dist(const S &S, const P &p) { return sqrt(dist2(S, p)); }

// 線分と線分の距離
double dist(const S &S1, const S &S2) {
  if (intersected(S1, S2))
    return 0;
  return sqrt(min(min(dist2(S1, S2.a), dist2(S1, S2.b)),
                  min(dist2(S2, S1.a), dist2(S2, S1.b))));
}

// 直線と点の距離
double dist(const L &L, const P &p) {
  return sqrt((double)SQ(cross(L.b - L.a, p - L.a)) / dist2(L.a, L.b));
}

// a -- bの間の円が入った時の、a - b間の距離
// 円の間に
double geodist(P a, P b, const C &c) {
  double r = c.r;
  S s(a, b);
  if (dist(s, c.c) > r)
    return abs(a - b);

  a -= c.c;
  b -= c.c;

  double L1 = abs(a);
  double t1 = arg(a) + acos(r / L1);
  if (t1 < 0)
    t1 += 2 * PI;
  double t2 = arg(a) - acos(r / L1);
  if (t2 < 0)
    t2 += 2 * PI;

  double L2 = abs(b);
  double t3 = arg(b) + acos(r / L2);
  if (t3 < 0)
    t3 += 2 * PI;
  double t4 = arg(b) - acos(r / L2);
  if (t4 < 0)
    t4 += 2 * PI;

  double theta = 2 * PI;
  theta = min(theta, min(abs(t1 - t4), 2 * PI - abs(t1 - t4)));
  theta = min(theta, min(abs(t2 - t3), 2 * PI - abs(t2 - t3)));
  return sqrt(L1 * L1 - r * r) + sqrt(L2 * L2 - r * r) + r * theta;
}

#pragma endregion

#pragma region 面積

// 多角形の面積
double area(const vector<P> &v) {
  double ans = 0;
  for (int i = 2; i < (int)v.size(); i++) {
    ans += cross(v[i - 1] - v[0], v[i] - v[0]);
  }
  return abs(ans) / 2;
}

// 三角形の面積
double area(const P &a, const P &b, const P &c) {
  return abs(cross(b - a, c - a)) / 2;
}

#pragma endregion

#pragma region 包含

// 凸包
vector<P> convex_hull(vector<P> &ps) {
  int n = ps.size(), k = 0;
  sort(ps.begin(), ps.end());
  vector<P> ch(2 * n);
  for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull
    while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;

  for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]) // upper-hull
    while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;

  ch.resize(k - 1);

  return ch;
}

// 三角形abcにpが含まれているかどうか(線上の場合も含む)
bool cover(const P &a, const P &b, const P &c, const P &p) {
  return area(a, b, c) + EPS >= area(a, b, p) + area(a, c, p) + area(b, c, p);
}

#pragma endregion

#pragma region 交点

// 円同士の交点
int intersect(const C &p, const C &q, P *w = NULL, P *z = NULL) {
  P a = q.c - p.c;
  // Point b = rot(a,PI / 2);
  P b(a.y, -a.x);
  double c = abs(a);
  if (c > p.r + q.r)
    return 0;
  b = b / c;

  double s = (p.r + q.r + c) / 2;
  double men = sqrt(s * (s - p.r) * (s - q.r) * (s - c));
  double l = 2 * men / c;
  double lp = sqrt(SQ(p.r) - SQ(l));

  a = a / c * lp;
  if (SQ(q.r) - SQ(p.r) - SQ(c) > 0) { // 考えている三角形の角が90度以上の場合
    a *= -1;
  }
  b = b * l;

  if (abs2(b) < EPS) {
    if (w && z)
      *w = *z = p.c + a;
    return 1;
  } else {
    if (w && z)
      *w = p.c + a + b, *z = p.c + a - b;
    return 2;
  }
}

// l : ax+by+c=0 に変換
inline void calc_abc(const L &l, double &a, double &b, double &c) {
  a = l.a.y - l.b.y;
  b = l.b.x - l.a.x;
  c = l.a.x * l.b.y - l.b.x * l.a.y;
}

// PからLへの垂線の足
P perp_foot(const P &p, const L &l) {
  double a, b, c;
  calc_abc(l, a, b, c);
  return p - P(a, b) * ((a * p.x + b * p.y + c) / (a * a + b * b));
}

// 円と直線の交点
int intersect(const C &c, const L &l, P *p = NULL, P *q = NULL) {
  P m = perp_foot(c.c, l);
  double d2 = abs2(c.c - m);
  if (c.r * c.r + EPS < d2)
    return 0;
  else if (abs(c.r * c.r - d2) < EPS) {
    if (p && q)
      *p = *q = m;
    return 1;
  } else {
    if (p && q) {
      P v;
      double n0 = abs2(l.a - m), n1 = abs2(l.b - m);
      if (n0 < n1)
        v = l.b - m, n0 = n1;
      else
        v = l.a - m;
      v *= sqrt((c.r * c.r - d2) / n0);
      *p = m + v, *q = m - v;
    }
    return 2;
  }
}

// 円と線分の交点
int intersect(const C &c, const S &s, P *p = NULL, P *q = NULL) {
  P pp, qq;
  int n = intersect(c, L(s.a, s.b), &pp, &qq);
  if (n == 0)
    return 0;
  else if (n == 1) {
    if (dot(pp - s.a, pp - s.b) < EPS) {
      if (p && q)
        *p = *q = pp;
      return 1;
    }
    return 0;
  } else {
    bool bp = (dot(pp - s.a, pp - s.b) < EPS);
    bool bq = (dot(qq - s.a, qq - s.b) < EPS);
    if (bp && bq) {
      if (p && q)
        *p = pp, *q = qq;
      return 2;
    }
    if (bp || bq) {
      if (p && q)
        *p = (bp ? pp : qq);
      return 1;
    }
    return 0;
  }
}

// 直線の交点
P intersect(const L &L1, const L &L2) {
  double a1 = cross(L1.b - L1.a, L2.b - L2.a);
  double a2 = cross(L1.b - L1.a, L1.b - L2.a);
  if (abs(a1) < EPS)
    return L1.a;
  return L2.a + (L2.b - L2.a) * (a2 / a1);
}

#pragma endregion

class CMP {
  C c;

public:
  CMP(const C &c) : c(c) {}
  bool operator()(const P &p, const P &q) const {
    double parg = arg(p - c.c);
    double qarg = arg(q - c.c);
    return parg < qarg;
  }
};

int main() {
  int n;
  while (cin >> n, n) {
    vector<C> vc(n);
    FOR(i, n) cin >> vc[i].c >> vc[i].r;

    double ans = 0;

    FOR(i, n) {
      vector<P> vp;
      FOR(j, n) if (i != j) {
        P p, q;
        int a = intersect(vc[i], vc[j], &p, &q);
        if (a == 1)
          vp.push_back(p);
        else if (a == 2)
          vp.push_back(p), vp.push_back(q);
      }

      sort(vp.begin(), vp.end(), CMP(vc[i]));

      ans += 2 * PI * vc[i].r;

      double dbg = 0;

      if (sz(vp) >= 2)
        FOR(j, sz(vp)) {
          P &p = vp[j], &q = vp[(j + 1) % sz(vp)];
          double parg = arg(p - vc[i].c);
          double qarg = arg(q - vc[i].c);
          double dist, md;
          if (qarg < parg)
            dist = (qarg - parg + 2 * PI);
          else
            dist = qarg - parg;
          md = parg + dist / 2;

          P a(cos(md), sin(md));
          a = a * vc[i].r + vc[i].c;

          bool covered = false;
          FOR(k, n) if (i != k) {
            if (abs2(a - vc[k].c) < SQ(vc[k].r)) {
              covered = true;
            }
          }

          if (covered) {
            ans -= dist * vc[i].r;
          }

          dbg += dist;
        }

      if (sz(vp) >= 2) {
        assert(abs(dbg - 2 * PI) < EPS);
      }
    }

    printf("%.12f\\n", ans);
  }

  return 0;
}