Problem:
Problem I:
Encircling Circles
You are given a set of circles
C
of a variety of radii (radiuses) placed at a variety of positions, possibly overlapping one another. Given a circle with radius
r
, that circle may be placed so that it encircles all of the circles in the set
C
if r is large enough.
There may be more than one possible position of the circle of radius
r
to encircle all the member circles of
C
. We define the region
U
as the union of the areas of encircling circles at all such positions. In other words, for each point in
U
, there exists a circle of radius
r
that encircles that point and all the members of
C
. Your task is to calculate the length of the periphery of that region
U
.
Figure I.1 shows an example of the set of circles
C
and the region
U
. In the figure, three circles contained in
C
are expressed by circles of solid circumference, some possible positions of the encircling circles are expressed by circles of dashed circumference, and the area
U
is expressed by a thick dashed closed curve.
Input
The input is a sequence of datasets. The number of datasets is less than 100.
Each dataset is formatted as follows.
n r
x
1
y
1
r
1
x
2
y
2
r
2
.
.
.
x
n
y
n
r
n
The first line of a dataset contains two positive integers,
n
and
r
, separated by a single space.
n
means the number of the circles in the set
C
and does not exceed 100.
r
means the radius of the encircling circle and does not exceed 1000.
Each of the
n
lines following the first line contains three integers separated by a single space. (
x
i
,
y
i
) means the center position of the
i
-th circle of the set
C
and
r
i
means its radius.
You may assume −500≤
x
i
≤500, −500≤
y
i
≤500, and 1≤
r
i
≤500.
The end of the input is indicated by a line containing two zeros separated by a single space.
Output
For each dataset, output a line containing a decimal fraction which means the length of the periphery (circumferential length) of the region
U
.
The output should not contain an error greater than 0.01. You can assume that, when
r
changes by ε (|ε| < 0.0000001), the length of the periphery of the region
U
will not change more than 0.001.
If
r
is too small to cover all of the circles in
C
, output a line containing only 0.0.
No other characters should be contained in the output.
Sample Input
1 10
5 5 7
2 12
5 5 7
8 6 3
3 10
3 11 2
2 1 1
2 16 3
3 15
-5 2 5
9 2 9
5 8 6
3 38
-25 -10 8
30 5 7
-3 35 11
3 39
-25 -10 8
30 5 7
-3 35 11
3 800
-400 400 2
300 300 1
300 302 1
3 800
400 -400 2
300 300 1
307 300 3
8 147
130 80 12
130 -40 12
-110 80 12
-110 -40 12
70 140 12
70 -100 12
-50 140 12
-50 -100 12
3 493
345 154 10
291 111 75
-275 -301 46
4 55
54 0 1
40 30 5
27 36 10
0 48 7
3 30
0 3 3
-3 0 4
400 0 3
3 7
2 3 2
-5 -4 2
-4 3 2
3 10
-5 -4 5
2 3 5
-4 3 5
4 6
4 6 1
5 5 1
1 7 1
0 1 1
3 493
345 154 10
291 111 75
-275 -301 46
5 20
-9 12 5
0 15 5
3 -3 3
12 9 5
-12 9 5
0 0
Output for the Sample Input
81.68140899333463
106.81415022205297
74.11215318612639
108.92086846105579
0.0
254.85616536128433
8576.93
...(truncated)

Submitted solutions:

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 10;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

//-----------------------------------
typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}

//円と円の交点
//交点が無かったらnullが返されます
//交点は大体いつも2つあるのでvector
vector<Point> is_cc(Circle c1, Circle c2) {
	vector<Point> res;
	ld d = abs(c1.p - c2.p);
	ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
	ld dfr = c1.r * c1.r - rc * rc;
	if (abs(dfr) < eps)dfr = 0.0;
	if (dfr < 0.0)return res;
	ld rs = sqrt(dfr);
	Point diff = (c2.p - c1.p) / d;
	res.push_back(c1.p + diff * Point(rc, rs));
	if (dfr != 0.0)res.push_back(c1.p + diff * Point(rc, -rs));
	return res;
}

int n, r;
void solve() {
	vector<Circle> c(n);
	rep(i, n) {
		int x, y, t; cin >> x >> y >> t;
		c[i] = { {(ld)x,(ld)y},(ld)t };
	}
	{
		vector<Circle> nc;
		vector<bool> ban(n);
		rep(i, n) {
			rep(j, n)if (i != j)if(!ban[j]) {
				ld dif = abs(c[j].p - c[i].p);
				if (dif + c[i].r <= c[j].r + eps) {
					ban[i] = true;
				}
			}
			if (!ban[i]) {
				nc.push_back(c[i]);
			}
		}
		swap(c, nc);
		n = c.size();
	}
	rep(i, n) {
		if (c[i].r > r) {
			cout << 0 << "\n"; return;
		}
	}

	if (n == 1) {
		ld ans = 2 * pi * (2*r-c[0].r);
		cout << ans << "\n";
		return;
	}
	vector<Circle> rc(n);
	rep(i, n) {
		rc[i].p = c[i].p;
		rc[i].r = r - c[i].r;
	}
	vector<pair<ld, int>> vp;
	vector<Point> pre;
	rep(i, n)Rep(j, i + 1, n) {
		vector<Point> cc = is_cc(rc[i], rc[j]);
		for (Point p : cc) {
			bool valid = true;
			for (Point pp : pre)if (abs(pp - p) < eps)valid = false;
			if (!valid)continue;
			rep(k, n) {
				ld len = abs(c[k].p - p) + c[k].r;
				if (len > r + eps)valid = false;
			}
			if (!valid)continue;
			pre.push_back(p);
			rep(k, n) {
				ld len = abs(c[k].p - p) + c[k].r;
				if (abs(len - r) < eps) {
					ld t = arg(p - c[k].p);
					vp.push_back({ t,k });
				}
			}
		}
	}
	if (vp.empty()) {
		//cout << "nande\n";
		cout << 0 << "\n"; return;
	}
	ld ans = 0;
	sort(all(vp));
	{
		vector<int> cnt(n);
		for (auto p : vp)cnt[p.second]++;
		vector<pair<ld, int>>cop;
		rep(i, vp.size())if (cnt[vp[i].second] != 1) {
			cop.push_back(vp[i]);
		}
		swap(vp, cop);
	}

	assert(vp.size()&&vp.size() % 2 == 0);
	rep(i, vp.size()) {
		int ni = (i + 1 == vp.size() ? 0 : i + 1);
		ld dt = vp[ni].first - vp[i].first;
		if (dt < 0)dt += 2 * pi;
		if (vp[i].second == vp[ni].second) {
			int id = vp[i].second;
			ans += dt * (2*r-c[id].r);
		}
		else {
			ans += dt * r;
		}
	}
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	//init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	while(cin>>n>>r,n)
	solve();
	return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3588
final_rank: 6

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105

enum Type{
	to_ccw,
	to_cw,
};

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

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

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

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Circle{
	Point center;
	double r;
};

struct Info{
	Info(){

		rad = 0;
		type = to_ccw;
	}
	Info(double arg_rad,Type arg_type){
		rad = arg_rad;
		type = arg_type;
	}
	bool operator<(const struct Info &arg) const{

		if(fabs(rad-arg.rad) > EPS){
			return rad < arg.rad;
		}else{

			return type < arg.type;
		}
	}
	bool operator==(const struct Info &arg) const{

		return fabs(rad-arg.rad) < EPS && type == arg.type;
	}

	double rad;
	Type type;
};


int N;
double R;
Circle C[SIZE];


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

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

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

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}



//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

int count_touch_C(Point P){

	int ret = 0;

	for(int i = 0; i < N; i++){
		if(fabs(calc_dist(P,C[i].center)+C[i].r-R) < EPS){

			ret++;
		}
		if(fabs(calc_dist(P,C[i].center)+C[i].r) > R+EPS){

			return -1;
		}
	}

	return ret;
}

//円aが円bを含むか判定
bool contain_check(Circle a,Circle b){

	return fabs(calc_dist(a.center,b.center)+b.r)+EPS < a.r;
}

//三辺が三角形を作れるか判定
bool triangle_check(double a,double b,double c){

	return (a+b > c+EPS) && (b+c > a+EPS) && (c+a > b+EPS);
}

void func(){

	bool first_check = true;

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf",&C[i].center.x,&C[i].center.y,&C[i].r);
		if(C[i].r > R+EPS){

			first_check = false;
		}
	}
	if(!first_check){

		printf("0.0\n");
		return;
	}
	if(N == 1){

		printf("%.10lf\n",(2*R-C[0].r)*2*M_PI);
		return;
	}

	double ans = 0;

	vector<Info> info;

	bool contain_FLG;

	for(int i = 0; i < N; i++){

		double one_R = 2*R-C[i].r;
		Point P = Point(C[i].center.x+(R-C[i].r),C[i].center.y); //rad0の位置にある包含円

		contain_FLG = false;
		for(int k = 0; k < N; k++){
			if(k == i)continue;

			if(contain_check(C[k],C[i])){

				contain_FLG = true;
				break;
			}
		}
		if(contain_FLG)continue;

		info.clear();

		int num_contain = 0;

		for(int k = 0; k < N; k++){
			if(k == i)continue;
			if(contain_check(C[i],C[k])){

				num_contain++;
				continue;
			}

			double len_i = R-C[i].r;
			double len_k = R-C[k].r;
			double len_ik = calc_dist(C[i].center,C[k].center);

			if(!triangle_check(len_i,len_k,len_ik)){
				continue;
			}


			double cos_theta = ((len_i*len_i+len_ik*len_ik)-len_k*len_k)/(2*len_i*len_ik);

			double rad_i = acos(cos_theta);

			for(int loop = 0; loop < 2; loop++){

				double roll_rad;
				if(loop == 0){
					//辺ikをcw回りに回転
					roll_rad = -rad_i;

				}else{
					//ccw回りに回転
					roll_rad = rad_i;
				}

				Point work = rotate(C[i].center,C[k].center,roll_rad);
				double tmp_rad = calc_rad(work-C[i].center);

				Point work_P = rotate(C[i].center,P,tmp_rad);

				int tmp_num = count_touch_C(work_P);

				if(tmp_num != -1){

					if(ccw(work_P,C[i].center,C[k].center) == COUNTER_CLOCKWISE){

						info.push_back(Info(tmp_rad,to_cw));

					}else{
						info.push_back(Info(tmp_rad,to_ccw));
					}
				}
			}
		}
		if(num_contain == N-1){ //他の全ての円を含む

			printf("%.10lf\n",one_R*2*M_PI);
			return;
		}

		if(info.size() == 0)continue;

		sort(info.begin(),info.end());
		info.erase(unique(info.begin(),info.end()),info.end()); //★★★3つ以上円に接する場合は、同じ地点が複数出てくる★★★

		int start = 0;
		//★★to_ccwとto_cwが交互に現れるはず★★
		if(info[0].type == to_cw){

			start = info.size()-1;
		}

		double one_rad = 0; //円iだけに引っかかる区間を求める
		double add_len = 0; //2つ以上引っ掛かる場合に、ccw順で一番近い円と作る弧の長さを足す

		for(int k = 0; k < info.size(); k += 2){

			double from = info[(start+k)%info.size()].rad;
			double to = info[(start+k+1)%info.size()].rad;

			if(to >= from){

				one_rad += to-from;

			}else{ //to < from;

				one_rad += 2*M_PI-(from-to);
			}

			Point from_P = rotate(C[i].center,P,from);
			double rad_from = calc_rad(C[i].center-from_P);//★★注意★★


			double min_rad = BIG_NUM;
			for(int a = 0; a < N; a++){
				if(a == i)continue;
				if(fabs(calc_dist(from_P,C[a].center)+C[a].r-R) > EPS){
					continue; //円弧に接していない小円はSKIP
				}

				double tmp_rad = calc_rad(C[a].center-from_P);
				if(tmp_rad > rad_from){

					min_rad = min(min_rad,tmp_rad-rad_from);

				}else{

					min_rad = min(min_rad,2*M_PI-(rad_from-tmp_rad));
				}
			}

			if(min_rad < M_PI+EPS){

				add_len += R*min_rad;
			}

			if(fabs(from-to) < EPS)continue; //★★同一地点★★

			Point to_P = rotate(C[i].center,P,to);
			double rad_to = calc_rad(C[i].center-to_P); //★★注意★★

			min_rad = BIG_NUM;
			for(int a = 0; a < N; a++){
				if(a == i)continue;

				if(fabs(calc_dist(to_P,C[a].center)+C[a].r-R) > EPS){
					continue; //円弧に接していない小円はSKIP
				}

				double tmp_rad = calc_rad(C[a].center-to_P);

				if(tmp_rad > rad_to){

					min_rad = min(min_rad,tmp_rad-rad_to);

				}else{

					min_rad = min(min_rad,2*M_PI-(rad_to-tmp_rad));
				}
			}

			if(min_rad < M_PI+EPS){

				add_len += R*min_rad;
			}
		}

		ans += add_len+one_R*one_rad;
	}

	printf("%.10lf\n",ans);
}

int main(){

	while(true){

		scanf("%d %lf",&N,&R);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3608
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout<<#x" = "<<((x))<<endl
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

/* 基本要素 */
typedef complex<double> Point;
typedef pair<Point, Point> Line;
typedef vector<Point> VP;
const double PI = acos(-1);
const double EPS = 1e-7; // 許容誤差^2
const double INF = 1e9;
#define X real()
#define Y imag()
// #define LE(n,m) ((n) < (m) + EPS)
#define LE(n,m) ((n) - (m) < EPS)
// #define GE(n,m) ((n) + EPS > (m))
#define GE(n,m) (EPS > (m) - (n))
#define EQ(n,m) (abs((n)-(m)) < EPS)

// 内積　dot(a,b) = |a||b|cosθ
double dot(Point a, Point b) {
  return a.X*b.X + a.Y*b.Y;
}

// 外積　cross(a,b) = |a||b|sinθ
double cross(Point a, Point b) {
  return a.X*b.Y - a.Y*b.X;
}

// 点の進行方向
// !!! 誤差に注意 !!! (掛け算したものとかなり小さいものを比べているので)
int ccw(Point a, Point b, Point c) {
  b -= a;  c -= a;
  if (cross(b,c) >  EPS) return +1;  // counter clockwise
  if (cross(b,c) < -EPS) return -1;  // clockwise
  if (dot(b,c)   < -EPS) return +2;  // c--a--b on line
  if (norm(b) < norm(c)) return -2;  // a--b--c on line or a==b
  return 0;                          // a--c--b on line or a==c or b==c
}

// 2円の交点
VP crosspointCC(Point a, double ar, Point b, double br) {
  VP ps;
  Point ab = b-a;
  double d = abs(ab);
  double crL = (norm(ab) + ar*ar - br*br) / (2*d);
  if (EQ(d, 0) || ar+EPS < abs(crL)) return ps;

  // 円が接する時、こことEPSの設定をうまくしないとsqrt(sub)がnanになるので注意
  double sub = ar*ar - crL*crL;
  if(EQ(sub,0)) sub = 0;

  Point abN = ab * Point(0, sqrt(sub) / d);
  Point cp = a + crL/d * ab;
  ps.push_back(cp + abN);
  if (!EQ(norm(abN), 0)) ps.push_back(cp - abN);
  return ps;
}

// aからbへの回転角（中心(0,0)）[-pi,+pi]
double angle(Point a,Point b){
  double t = arg(b)-arg(a);
  while(t>+PI) t-=2*PI;
  while(t<-PI) t+=2*PI;
  return t;
}

double solve(int n, double r){
    VP c(n);
    vector<double> cr(n);
    rep(i,n){
        int x,y;
        scanf(" %d %d %lf", &x, &y, &cr[i]);
        c[i] = Point(x,y);
    }

    // 円iを含むために、中心が移動できる範囲
    rep(i,n){
        cr[i] = r - cr[i];
        // dbg(cr[i]);
        if( !LE(0,cr[i]) ) return 0;
    }

    // どれかを内包する円は除去
    vector<bool> inner(n);
    rep(i,n){
        rep(j,n)if(i!=j){
            double D = abs(c[i]-c[j]);
            if( LE(D+cr[i], cr[j]) ) inner[j] = true;
        }
    }

    VP tttc;
    vector<double> tttr;
    rep(i,n){
        if(!inner[i]){
            tttc.pb(c[i]);
            tttr.pb(cr[i]);
        }
    }

    c = tttc;
    cr = tttr;
    n = c.size();

    if(n==1){
        return (cr[0]+r)*2*PI;
    }

    // n >= 2
    // 円iと円jの交点を求める
    using PPI = pair<Point,int>;
    vector<vector<PPI>> cps(n);

    rep(i,n)rep(j,i){
        VP cnd = crosspointCC(c[i], cr[i], c[j], cr[j]);
        if(cnd.size() == 0){
            // 交点がない時点で、2つを同時に包含できないのでおわり
            return 0;
        }
        else if(cnd.size() == 1){
            // 接するような円が見つかった時点で、その点にしか円はおけない
            // 置けるなら半径rの円
            bool ok = true;
            Point op = cnd[0];
            rep(k,n){
                if( !LE(abs(c[k]-op), cr[k]) ) ok = false;
            }

            if(ok) return r*2*PI;
            else return 0;
        }

        for(Point cp:cnd){
            cps[i].pb({cp,j});
            cps[j].pb({cp,i});
        }
    }

    // 偏角ソート
    double ans = 0;
    VP cand_pts;
    rep(i,n){
        vector<PPI> dat = cps[i];
        int sz = dat.size();

        // (偏角, index)
        using pd = pair<double,int>;
        vector<pd> stmp(sz);
        rep(j,sz){
            double theta = atan2(dat[j].fi.Y-c[i].Y, dat[j].fi.X-c[i].X);
            if( theta < -EPS ) theta = 2*PI + theta;
            stmp[j] = {theta, j};
        }

        sort(all(stmp));

        vector<double> cand_theta(sz);
        vector<int> valid(sz,1);
        rep(j,sz){
            double add = stmp[(j+1)%sz].fi - stmp[j].fi;
            if(add < -EPS) add += 2*PI;
            add /= 2;

            cand_theta[j] = stmp[j].fi + add;

            Point cp = c[i]+polar(cr[i],cand_theta[j]);
            // dbg(cp);
            // この点がokかチェック
            rep(k,n){
                if( !LE(abs(c[k]-cp), cr[k]) ) valid[j] = 0;
            }

            if(valid[j]){
                double theta = stmp[(j+1)%sz].fi - stmp[j].fi;
                if(theta < -EPS) theta += 2*PI;

                if(EQ(theta,0)) valid[j] = false;
                else ans += theta * (r+cr[i]);
            }
        }

        // printf(" --- %d \n",i);
        // dbg(dat);
        // dbg(stmp);
        // dbg(valid);

        rep(j,sz){
            if(valid[j]^valid[(j+1)%sz]){
                int idx = stmp[(j+1)%sz].se;
                cand_pts.pb(dat[idx].fi);
            }
        }
    }

    int CPZ = cand_pts.size();
    rep(i,CPZ){
        bool ok = true;
        rep(j,i){
            double dist = abs(cand_pts[j] - cand_pts[i]);
            if(EQ(dist,0)) ok = false;
        }
        if(!ok) continue;
        // dbg(cand_pts[i]);

        double mx_angle = 0;
        rep(ci,n)rep(cj,ci){
            bool valid_pair = false;

            for(Point ppp:crosspointCC(c[ci],cr[ci],c[cj],cr[cj])){
                double ddd = abs(ppp - cand_pts[i]);
                if(EQ(ddd,0)) valid_pair = true;
            }

            if(valid_pair){
                Point center = cand_pts[i];
                Point aaa = c[ci] - center;
                Point bbb = c[cj] - center;

                mx_angle = max(mx_angle, abs(angle(aaa,bbb)));
            }
        }

        ans += mx_angle*r;
    }

    return ans;
}

int main(){
    int n;
    double r;
    while( scanf(" %d %lf", &n, &r),n ){
        printf("%.15f\n", solve(n,r));
    }
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3820
final_rank: 7

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const double pi=acos(-1);
const int maxn=111;
int sgn(double x){return (x>eps)-(x<-eps);}
int sgn(double a,double b){return sgn(a-b);}
double sqr(double x){return x*x;}
struct P{
	double x,y;
	P(){}
	P(double x,double y):x(x),y(y){}
	double len2(){
		return sqr(x)+sqr(y);
	}
	double len(){
		return sqrt(len2());
	}
	void print(){
		printf("(%.3f,%.3f)\n",x,y);
	}
	void read(){
		scanf("%lf%lf",&x,&y);
	}
	P turn90(){return P(-y,x);}
	P norm(){return P(x/len(),y/len());}
	P rot(double rad){
		return P(x*cos(rad)+y*sin(rad),x*sin(rad)-y*cos(rad));
	}
};
bool operator==(P a,P b){
	return !sgn(a.x-b.x) and !sgn(a.y-b.y);
}
P operator+(P a,P b){
	return P(a.x+b.x,a.y+b.y);
}
P operator-(P a,P b){
	return P(a.x-b.x,a.y-b.y);
}
P operator*(P a,double b){
	return P(a.x*b,a.y*b);
}
P operator/(P a,double b){
	return P(a.x/b,a.y/b);
}
double operator^(P a,P b){
	return a.x*b.x + a.y*b.y;
}
double operator*(P a,P b){
	return a.x*b.y - a.y*b.x;
}
double det(P a,P b,P c){
	return (b-a)*(c-a);
}
double dis(P a,P b){
	return (b-a).len();
}
double Area(vector<P>poly){
	double ans=0;
	for(int i=1;i<poly.size();i++)
		ans+=(poly[i]-poly[0])*(poly[(i+1)%poly.size()]-poly[0]);
	return fabs(ans)/2;
}
struct L{
	P a,b;
	L(){}
	L(P a,P b):a(a),b(b){}
	P v(){return b-a;}
};
bool onLine(P p,L l){
	return sgn((l.a-p)*(l.b-p))==0;
}
bool onSeg(P p,L s){
	return onLine(p,s) and sgn((s.b-s.a)^(p-s.a))>=0 and sgn((s.a-s.b)^(p-s.b))>=0;
}
bool parallel(L l1,L l2){
	return sgn(l1.v()*l2.v())==0;
}
P intersect(L l1,L l2){
	double s1=det(l1.a,l1.b,l2.a);
	double s2=det(l1.a,l1.b,l2.b);
	return (l2.a*s2-l2.b*s1)/(s2-s1);
}
P project(P p,L l){
	return l.a+l.v()*((p-l.a)^l.v())/l.v().len2();
}
double dis(P p,L l){
	return fabs((p-l.a)*l.v())/l.v().len();
}
struct C{
	P o;
	double r;
	C(){}
	C(P _o,double _r):o(_o),r(_r){}
	void read(){
		o.read();
		scanf("%lf",&r);
	}
}c[maxn];
bool operator<(C a,C b){
	return a.r>b.r;
}
bool operator==(C c1,C c2){
	return c1.o==c2.o && sgn(c1.r-c2.r)==0;
}
double fix(double x){return sgn(x)?x:0;}
bool intersect(C a, C b, P &p1, P &p2) { 
	double s1 = (a.o - b.o).len();
	if (sgn(s1 - a.r - b.r) > 0 || sgn(s1 - fabs(a.r - b.r)) < 0) return false;
	double s2 = (a.r * a.r - b.r * b.r) / s1;
	double aa = (s1 + s2) * 0.5, bb = (s1 - s2) * 0.5;
	P o = (b.o - a.o) * (aa / (aa + bb)) + a.o;
	P delta = (b.o - a.o).norm().turn90() * sqrt(fix(a.r * a.r - aa * aa));
	p1 = o + delta, p2 = o - delta;
	return true;
}
int n;
double r;

double calcR(P O){
	double mxr=0;
	for(int i=1;i<=n;i++){
		double ri=0;
		ri=dis(c[i].o,O)+c[i].r;
		mxr=max(mxr,ri);
	}
	return mxr;
}

bool check(P O){
	double mxr=0;
	for(int i=1;i<=n;i++){
		double ri=0;
		ri=dis(c[i].o,O)+c[i].r;
		if(sgn(ri-r)>0)
			return false;
	}
	return true;
}
P O;
vector<P>vecO;
bool in(P p){

	if(sgn(dis(p,O)-r)<=0)
		return true;

	for(int i=1;i<=n;i++){
		C c1=c[i],c2;
		c2.o=p;
		c1.r=r-c1.r;
		c2.r=r;
		P p1,p2;
		if(c1==c2||!intersect(c1,c2,p1,p2))
			continue;
		if(check(p1)||check(p2))
			return true;
	}

	return false;
}
P at(P O,P dir){
	dir=dir.norm();
	double l=::r,r=20000;
	while(r-l>1e-9){
		double mid=(l+r)/2;
		if(in(O+dir*mid))
			l=mid;
		else r=mid;
	}
	return O+dir*l;
}
double calc(P a,P b,P c){
	
	L l1,l2;
	l1.a=(a+b)/2;
	l1.b=l1.a+(b-a).turn90();
	
	l2.a=(b+c)/2;
	l2.b=l2.a+(b-c).turn90();
	
	
	
	
	if(parallel(l1,l2))
		return dis(a,c);
	
	P O=intersect(l1,l2);
	double r=dis(O,a);
	
	
	double theta;
	theta = acos(((c-O)^(a-O))/r/r);
	
	return r*theta;	
}
double calc(double l,double r){
	
	double p=0.45;

	double m=l+(r-l)*p;
	
	P pl=at(O,P(1,0).rot(l));
	P pm=at(O,P(1,0).rot(m));
	P pr=at(O,P(1,0).rot(r));
	
	return calc(pl,pm,pr);
	
}
double simpl(double l,double r){
	double mid=(l+r)/2;
	
	
	double Sl=calc(l,mid);
	double Sr=calc(mid,r);
	double S=calc(l,r);
	
	if(sgn(S-Sl-Sr)==0)
		return S;
	return simpl(l,mid)+simpl(mid,r);
}

int main(){
	while(scanf("%d%lf",&n,&r)&&n){
		vecO.clear();
		for(int i=1;i<=n;i++){
			c[i].read();
		}
		
		sort(c+1,c+1+n);
		
		int m=0;
		static C nC[maxn];
		nC[++m]=c[1];
		for(int i=2;i<=n;i++){
			int flag=0;
			for(int j=1;j<=m;j++){
				double d=dis(c[i].o,nC[j].o);
				if(sgn(d-(nC[j].r-c[i].r))<=0){
					flag=1;
					break;
				}
			}
			if(!flag){
				nC[++m]=c[i];
			}
		}
		n=m;
		for(int i=1;i<=n;i++)
			c[i]=nC[i];
			
		if(n==1){
		
			if(sgn(c[1].r-r)<=0){
				printf("%.8f\n",2*pi*(r*2-c[1].r));
			}else{
				puts("0.0");
			}
			continue;
		}
		
		int flag=0;
		for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++){
			C c1=c[i],c2=c[j];
			double d=dis(c[i].o,c[j].o);
			c1.r=r-c1.r;
			c2.r=r-c2.r;
			P p1,p2;
			if(c1==c2||!intersect(c1,c2,p1,p2))
				continue;
			
			if(sgn(calcR(p1)-r)<=0){
				vecO.push_back(p1);
			}
			if(sgn(calcR(p2)-r)<=0){
				vecO.push_back(p2);
			}
		}
		
		if(vecO.empty()){
			puts("0.0");
			continue;
		}
		//cerr<<n<<endl;
		O=vecO.front();
		
		double ans=0;
		ans+=simpl(0,pi);
		ans+=simpl(pi,pi*2);
		printf("%.8f\n",ans);
		
	}
	return 0;
}
accuracy: 1
time_ms: 1550
memory_kb: 3500
final_rank: 8

code_snippet: #include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
using namespace std;
const double EPS = 1e-10;
const double INF = 1e+10;
const double PI = acos(-1);
int sig(double r) { return (r < -EPS) ? -1 : (r > +EPS) ? +1 : 0; }
inline double ABS(double a){return max(a,-a);}
struct Pt {
	double x, y;
	Pt() {}
	Pt(double x, double y) : x(x), y(y) {}
	Pt operator+(const Pt &a) const { return Pt(x + a.x, y + a.y); }
	Pt operator-(const Pt &a) const { return Pt(x - a.x, y - a.y); }
	Pt operator*(const Pt &a) const { return Pt(x * a.x - y * a.y, x * a.y + y * a.x); }
	Pt operator-() const { return Pt(-x, -y); }
	Pt operator*(const double &k) const { return Pt(x * k, y * k); }
	Pt operator/(const double &k) const { return Pt(x / k, y / k); }
	double ABS() const { return sqrt(x * x + y * y); }
	double abs2() const { return x * x + y * y; }
	double arg() const { return atan2(y, x); }
	double dot(const Pt &a) const { return x * a.x + y * a.y; }
	double det(const Pt &a) const { return x * a.y - y * a.x; }
};
double tri(const Pt &a, const Pt &b, const Pt &c) { return (b - a).det(c - a); }
pair<Pt,Pt> pCC(Pt a, double r, Pt b, double s) {
	double d = (b - a).ABS();
	double x = (d * d + r * r - s * s) / (d * 2);
	Pt e = (b - a) / d, w = e * Pt(0, 1) * sqrt(max(r * r - x * x, 0.0));
	return make_pair(a + e * x - w, a + e * x + w);
}
int iCC(Pt a, double r, Pt b, double s) {
	double d = (b - a).ABS();
	if (sig(d) == 0 && sig(r - s) == 0) return -1; // correspond
	if (sig(r - s - d) > 0) return +2; // r > s
	if (sig(s - r - d) > 0) return -2; // s > r
	return (sig(r + s - d) >= 0) ? 1 : 0;
}
Pt c[110];
double r[110];
vector<Pt> p[110];
vector<pair<int,int> > tp;
int v[11100];
double ad[110][110];
int main(){
	int a;
	double b;
	while(scanf("%d%lf",&a,&b),a){
		for(int i=0;i<a;i++){
			double x,y;
			scanf("%lf%lf%lf",&x,&y,r+i);
			c[i]=Pt(x,y);
		}
		for(int i=0;i<11100;i++)v[i]=0;
		for(int i=0;i<a;i++)p[i].clear();
		tp.clear();
		bool dame=false;
		for(int i=0;i<a;i++)if(r[i]>b+EPS)dame=true;
		for(int i=0;i<a;i++){
			for(int j=i+1;j<a;j++){
				if(iCC(c[i],b-r[i],c[j],b-r[j])==0)dame=true;
			}
		}
		if(dame){printf("0.0\n");continue;}
		for(int i=0;i<a;i++)for(int j=0;j<a;j++){
			if(iCC(c[i],b-r[i],c[j],b-r[j])==1){
				pair<Pt,Pt> t=pCC(c[i],b-r[i],c[j],b-r[j]);
				p[i].push_back(t.first);
				p[i].push_back(t.second);
			}
		}
		for(int i=0;i<a;i++){
			int n=p[i].size();
			if(n==0){
				p[i].push_back(c[i]+Pt(cos(1),sin(1)));
				p[i].push_back(c[i]+Pt(cos(1),sin(1)));
			}else{
				for(int j=0;j<n;j++){
					for(int k=0;k<n-1;k++){
						if((p[i][k]-c[i]).arg()>(p[i][k+1]-c[i]).arg()){
							swap(p[i][k],p[i][k+1]);
						}
					}
				}
				p[i].push_back(p[i][0]);
			}
		}
		double ret=0;
		for(int i=0;i<a;i++)for(int j=0;j<p[i].size()-1;j++){
			if(p[i].size()>2&&(p[i][j]-p[i][j+1]).ABS()<EPS)continue;
			double th=((p[i][j]-c[i]).arg()+(p[i][j+1]-c[i]).arg()+((j==p[i].size()-2)?PI*2:0))/2;
			Pt t=c[i]+Pt(cos(th),sin(th))*(b-r[i]);
			bool ok=true;
			for(int k=0;k<a;k++){
				if((t-c[k]).ABS()>b-r[k]+EPS){ok=false;break;}
			}
			if(ok){
			//	printf("%f %f %f %f\n",p[i][j].x,p[i][j].y,p[i][j+1].x,p[i][j+1].y);
				ret+=(b*2-r[i])*(((j==p[i].size()-2)?PI*2:0)+(p[i][j+1]-c[i]).arg()-(p[i][j]-c[i]).arg());
				tp.push_back(make_pair(i,j));
			}
		}
		int sz=tp.size();
		int at=0;
		int prev=-1;
		for(int i=0;i<a;i++)for(int j=0;j<a;j++){
			if(iCC(c[i],b-r[i],c[j],b-r[j])==1){
				pair<Pt,Pt> t=pCC(c[i],b-r[i],c[j],b-r[j]);
				double th=(t.first-c[j]).arg()-(t.first-c[i]).arg();
				if(th<0)th+=2*PI;
				if(th>PI)th=2*PI-th;
				ad[i][j]=th*b;
//				printf("%d %d: %f\n",i,j,ad[i][j]);
			}
		}
		for(int i=0;i<sz;i++){
			for(int j=0;j<sz;j++){
				if(at==j||(prev==j&&sz>2))continue;
				bool ok=false;
				if((p[tp[at].first][tp[at].second]-p[tp[j].first][tp[j].second]).ABS()<EPS)ok=true;
				if((p[tp[at].first][tp[at].second+1]-p[tp[j].first][tp[j].second]).ABS()<EPS)ok=true;
				if((p[tp[at].first][tp[at].second]-p[tp[j].first][tp[j].second+1]).ABS()<EPS)ok=true;
				if((p[tp[at].first][tp[at].second+1]-p[tp[j].first][tp[j].second+1]).ABS()<EPS)ok=true;
				if(ok){
					ret+=ad[tp[at].first][tp[j].first];
				//	printf("%d %d\n",tp[at].first,tp[j].first);
			//		printf("%f\n",ret);
					prev=at;at=j;break;
				}
			}
		}
		printf("%.12f\n",ret);
	}
}
accuracy: 1
time_ms: 340
memory_kb: 1668
final_rank: 4

code_snippet: #include<cstdio>
#include<vector>
#include<cmath>
#include<complex>
#include<algorithm>

using namespace std;

typedef double Real;
typedef complex<Real> Point;

const Real PI=acos(-1.0);
const Real eps=1e-8;

template<class T> bool eq(T a, T b){
	return abs(a-b)<eps;
}

template<class T> int sgn(T a){
	if(eq(a,(T)0)) return 0;
	if(a>0) return 1;
	return -1;
}

struct Circle:vector<Real> {
	Point c;
	Real r;
	Circle(){}
	Circle(Point c,Real r):c(c),r(r){}
};

Real R;
Circle cs[110];
int N;

Point getPolar(Point c,Point r,Real ang){
	return c+r*Point(cos(ang),sin(ang));
}

Real normalize(Real x){
	while(x<-PI) x+=PI*2;
	while(x>PI) x-=PI*2;
	return x;
}

Real arg(Point p){
	return atan2(p.imag(),p.real());
}

void iCC(Circle &c,Circle &c2){
	if(eq(c.c,c2.c)) return;
	Real d=abs(c.c-c2.c);
	Real r=c.r,r2=c2.r;
	if(sgn(d-(r+r2))>0) return;
	else if(sgn(d-(r+r2))==0){//out tan
		Real ang=normalize(arg(c2.c-c.c));
		c.push_back(ang);
	}else if(sgn(d-abs(r-r2))>0){//inter two points
		Real ang=arg(c2.c-c.c);
		Real ang2=acos((r*r+d*d-r2*r2)/(2*r*d));
		c.push_back(normalize(ang+ang2));
		c.push_back(normalize(ang-ang2));
	}else if(sgn(d-abs(r-r2))==0){//in tan
		if(r>r2){
			c.push_back(normalize(arg(c2.c-c.c)));
		}else{
			c.push_back(normalize(-arg(c2.c-c.c)));
		}
	}
	else{//contained
		return;
	}
}

bool changeCircles(){
	for(int i=0;i<N;i++){
		cs[i].r=R-cs[i].r;
		if(cs[i].r<eps) return false;
	}
	return true;
}

void getAllPoints(){
	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			if(i==j) continue;
			iCC(cs[i],cs[j]);
		}
	}
	for(int i=0;i<N;i++){
		cs[i].push_back(0);
		cs[i].push_back(PI);
	}
}

bool checkValidity(Point p){
	for(int i=0;i<N;i++){
		Real d=abs(p-cs[i].c);
		if(sgn(d-cs[i].r)>0) return false;
	}
	return true;
}

Real calcLength(){
	Real len=0,ang_sum=0;
	for(int i=0;i<N;i++){
		sort(cs[i].begin(),cs[i].end());
		for(int j=0;j<cs[i].size();j++){
			Real ang1=cs[i][j];
			Real ang2=j+1==cs[i].size()?cs[i][0]+PI*2:cs[i][j+1];
			Real ang=(ang1+ang2)/2;
			Point p=getPolar(cs[i].c,cs[i].r,ang);
			bool flg=checkValidity(p);
			if(flg){
				len+=(cs[i].r+R)*(ang2-ang1);
				ang_sum+=(ang2-ang1);
			}
		}
	}
	if(ang_sum<eps) return 0;
	Real len2=R*(PI*2-ang_sum);
	Real res=len+len2;
	return res;
}

void solve(){
	bool flg=changeCircles();
	if(flg==false){
		printf("0.0\n");
		return;
	}
	getAllPoints();
	Real ans=calcLength();
	printf("%f\n",ans);
}

void input(){
	int r;
	scanf("%d%d",&N,&r);
	if(N==0) exit(0);
	R=r;
	for(int i=0;i<N;i++){
		int x,y,r;
		scanf("%d%d%d",&x,&y,&r);
		cs[i].clear();
		cs[i]=Circle(Point(x,y),r);
	}
}

int main(){
	while(true){
		input();
		solve();
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1392
final_rank: 2

code_snippet: #include<cstdio>
#include<cmath>
#include<complex>
#include<vector>
#include<algorithm>

using namespace std;

const double eps=1e-9;
const double PI=3.14159265358979323846264;

typedef complex<double> Point;
typedef complex<double> Vector;

template<class T> bool eq(T a,T b){
	return abs(a-b)<eps;
}

double normalize(double ang){
	while(ang<0) ang+=PI*2;
	while(ang>PI*2) ang-=PI*2;
	return ang;
}

struct Circle{
	Point center;
	double r;
	vector<double> angles;//intersections
	Circle(){}
	Circle(Point p,double r):center(p),r(r){}
	bool isin(Point p){
		double dis=abs(p-center);
		return r>dis||eq(r,dis);
	}
	bool isin(Circle c){
		double d=abs(c.center-center)+c.r;
		return r>d;
	}
	Point getPoint(double theta){
		return center+(Point(cos(theta),sin(theta))*r);
	}
	Point onePoint(Circle c){
		double dis=abs(c.center-center);
		if(!eq(dis,r+c.r)){
			return Point(NAN,NAN);
		}
		Vector vec=c.center-center;
		return center+vec*(r/(r+c.r));
	}
	void add(Circle c){
		double r2=c.r;
		double d=abs(c.center-center);
		if(r+r2<d) return;
		double theta=acos((r*r+d*d-r2*r2)/(2.0*r*d));
		Vector vec=c.center-center;
		double phi=atan2(vec.imag(),vec.real());
		angles.push_back(normalize(phi+theta));
		angles.push_back(normalize(phi-theta));
	}
	bool haveCommon(Circle c){
		double d=abs(center-c.center);
		return d<r+c.r||eq(d,r+c.r);
	}
};

vector<Circle> C;
vector<Circle> centerArea;
vector<Circle> circles;
int N,R;

void solve(){
	for(int i=0;i<N;i++){
		if(C[i].r>R){
			printf("0.0\n");
			return;
		}
	}
	for(int i=0;i<N;i++){
		if(C[i].r==R){
			bool flg=true;
			for(int j=0;j<N;j++){
				if(i==j) continue;
				if(C[i].isin(C[j])==false) flg=false;
			}
			if(flg){
				printf("%.f\n",PI*2*R);
			}else{
				printf("0.0\n");
			}
			return;
		}
	}
	for(int i=0;i<N;i++){
		centerArea.push_back(Circle(C[i].center,R-C[i].r));
	}
	for(int i=0;i<N;i++){
		bool flg=true;
		for(int j=0;j<N;j++){
			if(i==j) continue;
			if(centerArea[i].isin(centerArea[j])){
				flg=false;
				break;
			}
		}
		if(flg) circles.push_back(centerArea[i]);
	}
	if(circles.size()==1){
		printf("%f\n",PI*2*(circles[0].r+R));
		return;
	}
	int M=circles.size();
	for(int i=0;i<M;i++) for(int j=i+1;j<M;j++){
		Point pt=circles[i].onePoint(circles[j]);
		if(isnan(pt.real())) continue;
		bool flg=true;
		for(int k=0;k<M;k++){
			if(i==k||j==k) continue;
			if(circles[k].isin(pt)==false) flg=false;
		}
		if(flg){
			printf("%f\n",PI*2*R);
		}else{
			printf("0.0\n");
		}
		return;
	}
	for(int i=0;i<M;i++) for(int j=0;j<M;j++){
		if(circles[i].haveCommon(circles[j])==false){
			printf("0.0\n");
			return;
		}
	}
	for(int i=0;i<M;i++) for(int j=0;j<M;j++){
		if(i==j) continue;
		circles[i].add(circles[j]);
	}
	double totalAng=0;
	double ans=0;
	for(int i=0;i<M;i++){
		Circle cur=circles[i];
		sort(cur.angles.begin(),cur.angles.end());
		for(int j=0;j<cur.angles.size();j++){
			double a=cur.angles[j];
			double b;
			if(j+1==cur.angles.size()){
				b=cur.angles[0]+PI*2;
			}else{
				b=cur.angles[j+1];
			}
			double mid=(a+b)/2;
			Point pt=cur.getPoint(mid);
			bool flg=true;
			for(int k=0;k<M;k++){
				if(circles[k].isin(pt)==false) flg=false;
			}
			if(flg){
				double curAng=b-a;
				ans+=(curAng*(R+cur.r));
				totalAng+=curAng;
			}
		}
	}
	if(totalAng==0){
		printf("0.0\n");
	}else{
		ans+=(PI*2-totalAng)*R;
		printf("%f\n",ans);
	}
}

void init(){
	C.clear();
	centerArea.clear();
	circles.clear();
}

int main(){
	while(true){
		scanf("%d%d",&N,&R);
		if(N==0&&R==0) break;
		init();
		for(int i=0;i<N;i++){
			int x,y,r;
			scanf("%d%d%d",&x,&y,&r);
			C.push_back(Circle(Point(x,y),r));
		}
		solve();
	}
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 1372
final_rank: 3

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cassert>
using namespace std;

const double EPS=1e-8;

struct pt {
	double x,y;
	pt() {}
	pt(double x_, double y_) : x(x_), y(y_) {}
	pt operator + (const pt& p) const { return pt(x+p.x,y+p.y); }
	pt operator - (const pt& p) const { return pt(x-p.x,y-p.y); }
	double mod2() const { return x*x+y*y; }
	double mod() const { return sqrt(mod2()); }
	double arg() const { return atan2(y,x); }
	static pt polar(double r, double theta) { return pt(r*cos(theta),r*sin(theta)); }
	bool operator == (const pt& p) const { return x==p.x && y==p.y; }
	bool operator < (const pt& p) const { return false; }
};

istream& operator >> (istream& i, pt& p) { return i >> p.x >> p.y; }

typedef vector<pt> VP;
typedef vector<int> VI;
typedef vector<double> VD;
typedef pair<double,pt> PDP;
typedef vector<PDP> VC;

inline double sq(double x) { return x*x; }

int main() {
	int n,R;
	while(cin >> n >> R && n) {
		double o=0;
		double ret=0;
		double rem=2*M_PI;
		bool exists=false;
		VC cc(n);
		for (int i=0;i<n;++i) {
			cin >> cc[i].second >> cc[i].first;
			cc[i].first=R-cc[i].first;
		}
		sort(cc.begin(),cc.end());
		VP c;
		VD r;
		for (int i=0;i<n;++i) {
			if (cc[i].first<0) goto res;
			for (int j=0;j<i;++j) {
				if ((cc[i].second-cc[j].second).mod2()<=sq(cc[i].first-cc[j].first)) goto redundant;
			}
			r.push_back(cc[i].first);
			c.push_back(cc[i].second);
			redundant:;
		}
		n=c.size();
		for (int i=0;i<n;++i) {
			VD alpha;
			alpha.push_back(0);
			alpha.push_back(2*M_PI);
			for (int j=0;j<n;++j) {
				if (j==i) continue;
				pt v=c[j]-c[i];
				if (v.mod2()>sq(r[i]+r[j])) goto res;
				if (v.mod2()<sq(r[i]-r[j])) continue;
				double theta=v.arg();
//				cerr << (v.mod2()+sq(r[i])-sq(r[j])) << " / " << (2*v.mod()*r[i]) << endl;
				double co=(v.mod2()+sq(r[i])-sq(r[j]))/(2*v.mod()*r[i]);
				//assert(co>=-1);
				//assert(co<=1);
				if (co<-1) co=-1;
				if (co>1) co=1;
				double phi=acos(co);
//				cerr << i << " intersects with " << j << " at " << theta-phi << " and " << theta+phi << endl;
				alpha.push_back(theta+phi-2*M_PI);
				alpha.push_back(theta+phi);
				alpha.push_back(theta+phi+2*M_PI);
				alpha.push_back(theta-phi-2*M_PI);
				alpha.push_back(theta-phi);
				alpha.push_back(theta-phi+2*M_PI);
			}
			sort(alpha.begin(),alpha.end());
			for(int k=0;alpha[k]<2*M_PI;++k) {
				if (alpha[k]<0) continue;
				double delta=alpha[k+1]-alpha[k];
				double beta=(alpha[k]+alpha[k+1])/2;
				pt mid=c[i]+pt::polar(r[i],beta);
				for (int j=0;j<n;++j) {
					if ((mid-c[j]).mod()-EPS>r[j]) goto skip;
				}
//				cerr << "added an interval " << alpha[k] << " -- " << alpha[k+1] << " at " << i << " w/radius " << r[i]+R << endl;
				exists=true;
				ret+=(r[i]+R)*delta;
				rem-=delta;
				skip:;
			}
		}
		if (exists) o=ret+R*rem;
		res:
		if (o) printf("%.3f\n",o);
		else printf("0.0\n");
	}
}
accuracy: 1
time_ms: 10
memory_kb: 0
final_rank: 1