Language: C++

#include<iostream>
#include<complex>
#include<cmath>
#include<vector>
#include<iomanip>
#include<set>
#include<functional>
#include<algorithm>
#include<cstdlib>


using namespace std;

typedef double elem;
typedef complex<elem> point, vec;
typedef pair<point,point> pp;
const elem eps = 1e-8;
const elem inf = 1e40;
const elem pi = 2*acos(0.0);

#define foreach(it,o) for(__typeof((o).begin()) it = (o).begin(); (it) != (o).end(); it++)

bool eq(elem a, elem b){
  return abs(b-a)<eps;
}
bool lt(elem a, elem b){
  return !eq(a,b) && a<b;
}
bool leq(elem a, elem b){
  return eq(a,b) || a<b;
}

elem varg(const vec &a, const vec &b){
  elem ret = arg(a)-arg(b);
  if(ret<0)ret += 2*pi;
  if(ret>2*pi)ret -= 2*pi;
  if(eq(ret,2*pi))ret= 0;
  return ret;
}

struct circle{
  point c;
  elem r;
  circle():c(0,0),r(0){}
  circle(const point &c, elem r):c(c),r(r){} 
};

enum cir_rel{cir_1c=0x01,cir_1ic=0x02,cir_0c=0x04,cir_cont=0x08,cir_2c=0x10,cir_same=0x20};

int circlesRel(const circle &c1, const circle &c2){
  elem d = abs(c1.c- c2.c);
  elem r1=c1.r, r2=c2.r;
  if(lt(r1,r2))swap(r1,r2);
  if(eq(d,r1+r2))return cir_1c;
  if(eq(d,r1-r2))return cir_1ic;
  if(lt(r1+r2,d))return cir_0c;
  if(lt(d,r1-r2))return cir_cont;
  if(lt(d,r1+r2))return cir_2c;
  if(eq(abs(c1.c-c2.c),0)&&eq(c1.r,c2.r))return cir_same;
}

bool inCircle(const circle &a, const circle &b){
  return circlesRel(a,b) & (cir_1ic|cir_cont|cir_same);
}

void removeIncircles(vector<circle> &vc){
  for(int i = 0; i < (int)vc.size(); ++i){
    for(int j = i+1; j < (int)vc.size(); ++j){
      if( inCircle(vc[i],vc[j]) ){
        vc.erase( vc.begin() + j );
        j = i;
      }
    }
  }
}

vec uvec(const vec &a){ return a / abs(a); }

int intersectionCC(const circle &c1, const circle &c2, pp &p){
  if( !(circlesRel(c1,c2) & (cir_1ic|cir_1c|cir_2c)))return 0;
  elem d = abs(c1.c-c2.c);
  vec ab = c2.c- c1.c;
  elem k = (c1.r*c1.r-c2.r*c2.r+d*d) / (2*d*d);
  point t = k*ab+c1.c;
  elem x = sqrt(c1.r*c1.r-(d*d*k*k));
  
  if( eq(x,0) ){
    p.first = t; return 1;
  }else{
    p.first = x * uvec(ab*point(0,1))+t;
    p.second = x * uvec(ab*point(0,-1))+t;
    return 2;
  }
}

bool checkAll(const circle &c, const vector<circle> &vc){
  for(int i = 0; i < (int)vc.size(); ++i){
    if( lt(c.r, abs(vc[i].c-c.c)+vc[i].r ) ) return false;
  }
  return true;
}

int getEncirclingCircle(elem r, const circle &c1, const circle &c2, const vector<circle> &vc,
                        pair<circle,circle> &ret){
  circle x(c1.c, r-c1.r);
  circle y(c2.c, r-c2.r);

  pp p;
  int cc_ret = intersectionCC(x,y,p);
  if( cc_ret == 1 ){
    ret.first = circle(p.first,r);
    if( !checkAll(ret.first, vc) ) cc_ret--;
  }else if( cc_ret == 2 ){
    ret.first = circle(p.first,r);
    ret.second = circle(p.second,r);
    if( !checkAll(ret.first, vc) ){ cc_ret--; ret.first = ret.second;
    }else if( !checkAll(ret.second, vc) ) cc_ret--;
    if( !checkAll(ret.first, vc) ) cc_ret--;
  }
  return cc_ret;
}

struct cmp{
  point center;
  cmp(point c):center(c){}
  bool operator()(const point &a, const point &b)const{
    return varg(point(1,0),a-center)<varg(point(1,0),b-center);
  }
  bool operator()(const circle &a, const circle &b)const{
    return varg(point(1,0),a.c-center)<varg(point(1,0),b.c-center);
  }
};

point calcCoG(const vector<circle> &vc){
  point ret(0,0);
  for(int i = 0; i < (int)vc.size(); ++i){
    ret += vc[i].c;
  }
  return ret * (1./(double)vc.size());
}

set<int> getTangSet(const circle &bc, const vector<circle> &vc){
  set<int> ret;
  for(int i = 0; i < (int)vc.size(); ++i){
    if( eq(abs(vc[i].c-bc.c) + vc[i].r, bc.r) ){
      ret.insert(i);
    }
  }
  return ret;
}

set<int> getCommon(const set<int> &a, const set<int> &b){
  set<int> ret;
  foreach(it,a)foreach(it2,b)if( *it == *it2 )ret.insert( *it );
  return ret;
}

int main()
{
  int n;
  elem R;

  while( cin >> n >> R ){

    if( n == 0 && eq(R,0) ) break;
    
    vector<circle> vc;
    elem res = 0;
    
    for(int i = 0; i < n; ++i){
      elem x,y,r;
      cin >> x >> y >> r;
      vc.push_back( circle(point(x,y),r) );
    }

    removeIncircles( vc );
    n = vc.size();

    sort(vc.begin(), vc.end(), cmp(calcCoG(vc)));

    if( n == 1 ){
      res = 2*pi * (2*R - vc.front().r);
    }else if( n >= 2 ){
      vector<circle> blueCircles;
      
      for(int i = 0; i < n; ++i){
        vector<circle> cand;
        for(int j = i+1; j < n; ++j){
          pair<circle,circle> tmp;
          int ret = getEncirclingCircle(R,vc[i],vc[j],vc,tmp);
          if(ret>=1)cand.push_back(tmp.first);
          if(ret>=2)cand.push_back(tmp.second);
        }
        if(cand.size()==0)continue;
        blueCircles.insert(blueCircles.end(), cand.begin(), cand.end());
      }
      
      // elim duplicates
      for(int i = 0; i < (int)blueCircles.size(); ++i){
        for(int j = i+1; j < (int)blueCircles.size(); ++j){
          if( eq(abs(blueCircles[i].c-blueCircles[j].c),0) ){
            blueCircles.erase( blueCircles.begin() + j );
            j = i;
          }
        }
      }
      
      sort(blueCircles.begin(), blueCircles.end(), cmp(calcCoG(vc)));
      // blueCircles)));

      
      /*
      cout << blueCircles.size() << endl;      
      for(int i = 0; i < (int)vc.size(); ++i){
        cout << "circle(" <<vc[i].c.real() <<','<<vc[i].c.imag()<<','<< vc[i].r <<");"<< endl;
      }
      cout << endl;
      for(int i = 0; i < (int)blueCircles.size(); ++i){
        cout << "circle(" <<blueCircles[i].c.real() <<','<<blueCircles[i].c.imag()<<','<< blueCircles[i].r <<");"<< endl;
      }
      cout << "-----" << endl;
      */

      int cur = 0;
      if( blueCircles.size() > 2 ){
        
        for(int i = 0; i < (int)blueCircles.size(); ++i){
          circle bc0 = blueCircles[i];
          circle bc1 = blueCircles[(i+1)%blueCircles.size()];
          
          set<int> tangCSet0 = getTangSet(bc0, vc);
          set<int> tangCSet1 = getTangSet(bc1, vc);
          set<int> common = getCommon(tangCSet0, tangCSet1);
          
          vector<int> vcommon = vector<int>(common.begin(), common.end());

          /*
          cout<<setprecision(3);
          foreach(it,tangCSet0){
            cout << vc[*it].c << ' ' << vc[*it].r << ',';
          }
          cout << endl;
          foreach(it2,tangCSet1){
            cout << vc[*it2].c << ' ' << vc[*it2].r << ',';
          }
          cout << endl;

          for(int j = 0; j < (int)vcommon.size(); ++j){
            cout << vcommon[j] << ' ';
          }
          cout << endl;
          */

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

          sort(vcommon.begin() , vcommon.end());
          cur = vcommon.front();

          elem tmp = varg(bc0.c-vc[cur].c, bc1.c-vc[cur].c);
          if( lt(pi,tmp) ) tmp = 2*pi - tmp;
          res += tmp * (2*R - vc[cur].r);
        }

      }else if( blueCircles.size() == 2 ){
        circle bc0 = blueCircles[0];
        circle bc1 = blueCircles[1];
        
        set<int> tangCSet0 = getTangSet(bc0, vc);
        set<int> tangCSet1 = getTangSet(bc1, vc);
        set<int> common = getCommon(tangCSet0, tangCSet1);
        
        vector<int> vcommon = vector<int>(common.begin(), common.end());
        
        assert(vcommon.size()>1);

        //cout << "common : ";
        //for(int i = 0; i < vcommon.size(); ++i)cout << vcommon[i] << ' ';
        //cout << endl;

        vector<int> p;
        elem max_arg = 0;
        for(int i = 0; i < (int)vcommon.size(); ++i){
          for(int j = i+1; j < (int)vcommon.size(); ++j){
            elem tmp = varg(vc[vcommon[i]].c-bc0.c,vc[vcommon[j]].c-bc0.c);
            if( lt(pi,tmp) ) tmp = 2*pi - tmp;
            if( lt(max_arg, tmp) ){
              max_arg = tmp;
              p.clear();
              p.push_back(vcommon[i]);p.push_back(vcommon[j]);
            }
          }
        }

        for(int i = 0; i < (int)p.size(); ++i){
          // cout << p[i] << ' ';
          elem tmp = varg(bc0.c-vc[p[i]].c, bc1.c - vc[p[i]].c);
          if( lt(pi,tmp) ) tmp = 2*pi-tmp;
          res += tmp * (2*R-vc[p[i]].r);
        }
        // cout << endl;
        
      }
      

      for(int i = 0; i < (int)blueCircles.size(); ++i){
        circle bc = blueCircles[i];
        set<int> tangCSet = getTangSet(bc, vc);
        vector<int> vtang = vector<int>(tangCSet.begin(), tangCSet.end());
        vector<circle> tangc;
        for(int j = 0; j < (int)vtang.size(); ++j){
          tangc.push_back(vc[vtang[j]]);
        }
        sort(tangc.begin(),tangc.end(),cmp(bc.c));
        assert(tangc.size()>1);
        for(int j = 0; j < (int)tangc.size(); ++j){
          elem tmp = 2*pi - varg(tangc[j].c-bc.c, tangc[(j+1)%tangc.size()].c-bc.c);
          if( leq(tmp,pi) ){
            res += tmp * bc.r;
          }
        }
      }
    }

    cout << fixed << setprecision(16) << res << endl;
  }
  return 0;
}

Compiler output:
a.cc: In function 'int main()':
a.cc:274:9: error: 'assert' was not declared in this scope
  274 |         assert(vcommon.size()>1);
      |         ^~~~~~
a.cc:10:1: note: 'assert' is defined in header '<cassert>'; this is probably fixable by adding '#include <cassert>'
    9 | #include<cstdlib>
  +++ |+#include <cassert>
   10 | 
a.cc:314:9: error: 'assert' was not declared in this scope
  314 |         assert(tangc.size()>1);
      |         ^~~~~~
a.cc:314:9: note: 'assert' is defined in header '<cassert>'; this is probably fixable by adding '#include <cassert>'
a.cc: In function 'int circlesRel(const circle&, const circle&)':
a.cc:60:1: warning: control reaches end of non-void function [-Wreturn-type]
   60 | }
      | ^