Problem:
Score : 600 points

Problem Statement

On the xy-plane, Snuke is going to travel from the point (x_s, y_s) to the point (x_t, y_t).
He can move in arbitrary directions with speed 1.
Here, we will consider him as a point without size.

There are N circular barriers deployed on the plane.
The center and the radius of the i-th barrier are (x_i, y_i) and r_i, respectively.
The barriers may overlap or contain each other.

A point on the plane is exposed to cosmic rays if the point is not within any of the barriers.

Snuke wants to avoid exposure to cosmic rays as much as possible during the travel.
Find the minimum possible duration of time he is exposed to cosmic rays during the travel.

Constraints

All input values are integers.

-10^9 ≤ x_s, y_s, x_t, y_t ≤ 10^9

(x_s, y_s) ≠ (x_t, y_t)

1≤N≤1,000

-10^9 ≤ x_i, y_i ≤ 10^9

1 ≤ r_i ≤ 10^9

Input

The input is given from Standard Input in the following format:

x_s y_s x_t y_t
N
x_1 y_1 r_1
x_2 y_2 r_2
:
x_N y_N r_N

Output

Print the minimum possible duration of time Snuke is exposed to cosmic rays during the travel.
The output is considered correct if the absolute or relative error is at most 10^{-9}.

Sample Input 1

-2 -2 2 2
1
0 0 1

Sample Output 1

3.6568542495

An optimal route is as follows:

Sample Input 2

-2 0 2 0
2
-1 0 2
1 0 2

Sample Output 2

0.0000000000

An optimal route is as follows:

Sample Input 3

4 -2 -2 4
3
0 0 2
4 0 1
0 4 1

Sample Output 3

4.0000000000

An optimal route is as follows:

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;
using System.Collections.Generic;

namespace Contest
{
    class Program
    {
        static void Main(string[] args)
        {
            ARC064.E();
        }
        class ARC064
        {
            public static void C()
            {
                var N = Read.Int();
                var X = Read.Long();
                var A = Read.LongN();

                long count = 0;
                if (A[0] > X) { count += A[0] - X;A[0] = X; }
                for(int i = 1; i < N; ++i)
                {
                    if (A[i] + A[i - 1] > X)
                    {
                        count += A[i] + A[i - 1] - X;
                        A[i] = X - A[i - 1];
                    }
                }
                Console.WriteLine(count);
            }
            public static void D()
            {
                var S = Read.Str();
                var N = S.Length;
                Console.WriteLine(S[0] == S[N - 1] ^ N % 2 > 0 ? "First" : "Second");
            }
            public static void E()
            {
                var XS = Read.Long();
                var YS = Read.Long();
                var XT = Read.Long();
                var YT = Read.Long();
                var N = Read.Int();
                var XYR = Enumerable.Range(0, N).Select(i => Read.LongN()).ToList();
                XYR.Add(new long[] { XS, YS, 0 });
                XYR.Add(new long[] { XT, YT, 0 });
                var Adj = new Dictionary<int, Dictionary<int, double>>();
                for(int i = 0; i < N + 2; ++i)
                {
                    Adj.Add(i, new Dictionary<int, double>());
                }
                Func<long, long, long, long, double> calcDist = (x1, y1, x2, y2) =>
                {
                    double dx = x1 - x2, dy = y1 - y2;
                    return Math.Sqrt(dx * dx + dy * dy);
                };
                for (int i = 0; i < N+2; ++i)
                {
                    for(int j = i + 1; j < N + 2; ++j)
                    {
                        var d = Math.Max(0, calcDist(XYR[i][0], XYR[i][1], XYR[j][0], XYR[j][1]) - XYR[i][2] - XYR[j][2]);
                        Adj[i].Add(j, d);
                        Adj[j].Add(i, d);
                    }
                }
                var dist = Util.DijkstraDouble(Adj, N + 2, (N + 2) * (N + 1) / 2, N);
                Console.WriteLine(dist[N + 1]);
            }
        }
        class Util
        {
            public class PriorityQueue<T> where T : IComparable
            {
                private IComparer<T> _comparer = null; private bool _isAsc = true; private T[] _heap; private int _sz = 0;
                public PriorityQueue(int maxSize, IComparer<T> comparer) { _heap = new T[maxSize]; _comparer = comparer; }
                public PriorityQueue(int maxSize, bool isAsc = true) { _heap = new T[maxSize]; _isAsc = isAsc; }
                private int Compare(T x, T y) { if (_comparer != null) { return _comparer.Compare(x, y); } return _isAsc ? x.CompareTo(y) : y.CompareTo(x); }
                public void Push(T x) { var i = _sz++; while (i > 0) { var p = (i - 1) / 2; if (Compare(_heap[p], x) <= 0) { break; } _heap[i] = _heap[p]; i = p; } _heap[i] = x; }
                public T Pop() { T ret = _heap[0]; T x = _heap[--_sz]; int i = 0; while (i * 2 + 1 < _sz) { int a = i * 2 + 1; int b = i * 2 + 2; if (b < _sz && Compare(_heap[b], _heap[a]) < 0) { a = b; } if (Compare(_heap[a], x) >= 0) { break; } _heap[i] = _heap[a]; i = a; } _heap[i] = x; return ret; }
                public int Count() { return _sz; }
                public T Peek() { return _heap[0]; }
                public bool Contains(T x) { for (int i = 0; i < _sz; i++) if (x.Equals(_heap[i])) return true; return false; }
            }
            public class MyTuple<T1, T2> : IComparable where T1 : IComparable<T1>
            {
                public readonly T1 Item1; public readonly T2 Item2;
                public MyTuple(T1 item1, T2 item2) { Item1 = item1; Item2 = item2; }
                public int CompareTo(object obj) { return Item1.CompareTo(((MyTuple<T1, T2>)obj).Item1); }
            }
            public static double[] DijkstraDouble(Dictionary<int, Dictionary<int, double>> adj, int N, int M, int start)
            {
                double INF = 1e20;
                var dist = Enumerable.Range(0, N + 1).Select(i => INF).ToArray();
                var queue = new PriorityQueue<MyTuple<double, int>>(N + M + 100);
                dist[start] = 0;
                queue.Push(new MyTuple<double, int>(0, start));
                while (queue.Count() > 0)
                {
                    var kvp = queue.Pop();
                    var d = kvp.Item1; var v = kvp.Item2;
                    if (dist[v] < d) { continue; }
                    foreach (var kvp2 in adj[v])
                    {
                        var newV = kvp2.Key;
                        var newD = dist[v] + kvp2.Value;
                        if (newD < dist[newV])
                        {
                            dist[newV] = newD;
                            queue.Push(new MyTuple<double, int>(newD, newV));
                        }
                    }
                }
                return dist;
            }
        }

        static class Read
        {
            static Queue<string> queue = new Queue<string>();
            static void Enqueue() { var ss = Console.ReadLine().Split(' '); foreach (var s in ss) { queue.Enqueue(s); } }
            public static int Int() { if (queue.Count == 0) { Enqueue(); } return Convert.ToInt32(queue.Dequeue()); }
            public static long Long() { if (queue.Count == 0) { Enqueue(); } return Convert.ToInt64(queue.Dequeue()); }
            public static string Str() { if (queue.Count == 0) { Enqueue(); } return queue.Dequeue(); }
            public static int[] IntN() { return Console.ReadLine().Split(' ').Select(s => Convert.ToInt32(s)).ToArray(); }
            public static long[] LongN() { return Console.ReadLine().Split(' ').Select(s => Convert.ToInt64(s)).ToArray(); }
            public static ulong[] ULongN() { return Console.ReadLine().Split(' ').Select(s => Convert.ToUInt64(s)).ToArray(); }
            public static string[] StrN() { return Console.ReadLine().Split(' '); }
            public static Tuple<int, int>[] TupleInt(int n) { List<Tuple<int, int>> list = new List<Tuple<int, int>>(); for (int i = 0; i < n; ++i) { var ab = Read.IntN(); list.Add(new Tuple<int, int>(ab[0], ab[1])); } return list.ToArray(); }
            public static Tuple<long, long>[] TupleLong(int n) { List<Tuple<long, long>> list = new List<Tuple<long, long>>(); for (int i = 0; i < n; ++i) { var ab = Read.LongN(); list.Add(new Tuple<long, long>(ab[0], ab[1])); } return list.ToArray(); }
            public static Tuple<string, string>[] TupleStr(int n) { List<Tuple<string, string>> list = new List<Tuple<string, string>>(); for (int i = 0; i < n; ++i) { var ab = Read.StrN(); list.Add(new Tuple<string, string>(ab[0], ab[1])); } return list.ToArray(); }
            public static Tuple<double, double>[] TupleDouble(int n) { List<Tuple<double, double>> list = new List<Tuple<double, double>>(); for (int i = 0; i < n; ++i) { var ab = Read.LongN(); list.Add(new Tuple<double, double>(ab[0], ab[1])); } return list.ToArray(); }
            public static long[,] LongMatrix(int r, int c)
            {
                var mat = new long[r, c];
                for (int i = 0; i < r; ++i)
                {
                    var x = Read.LongN();
                    for (int j = 0; j < c; ++j)
                    {
                        mat[i, j] = x[j];
                    }
                }
                return mat;
            }
            public static Dictionary<int, HashSet<int>> AdjacencyList(int N, int M, bool isDirectional = false)
            {
                Dictionary<int, HashSet<int>> dict = new Dictionary<int, HashSet<int>>();
                for (int i = 0; i <= N; ++i) { dict.Add(i, new HashSet<int>()); }
                for (int i = 0; i < M; ++i)
                {
                    var ab = Read.IntN(); dict[ab[0]].Add(ab[1]);
                    if (!isDirectional) { dict[ab[1]].Add(ab[0]); }
                }
                return dict;
            }
            public static Dictionary<int, Dictionary<int, long>> AdjacencyListWithWeight(int N, int M)
            {
                Dictionary<int, Dictionary<int, long>> dict = new Dictionary<int, Dictionary<int, long>>();
                for (int i = 0; i <= N; ++i)
                {
                    dict.Add(i, new Dictionary<int, long>());
                }
                for (int i = 0; i < M; ++i)
                {
                    var ab = Read.IntN();
                    dict[ab[0]].Add(ab[1], ab[2]);
                    dict[ab[1]].Add(ab[0], ab[2]);
                }
                return dict;
            }
        }
    }
}