#include <bits/stdc++.h>
using namespace std;
 
#define SQR(n) ((n) * (n))
#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)
 
struct Point
{
  double x, y;
 
  Point () {}
  Point (double x, double y) : x(x), y(y) {}
 
  void input() { scanf("%lf %lf", &x, &y); }
  double abs() { return (sqrt(norm())); }
  double norm() { return (SQR(x) + SQR(y)); }
 
  Point operator + (Point d) { return (Point(x + d.x, y + d.y)); }
  Point operator - (Point d) { return (Point(x - d.x, y - d.y)); }
  Point operator * (double a) { return (Point(x * a, y * a)); }
  Point operator / (double a) { return (Point(x / a, y / a)); }
 
  bool operator < (const Point d) const {
    if(x < d.x) return (true);
    if(x > d.x) return (false);
    return (y < d.y);
  }
};
 
typedef Point Vector;
typedef vector < Point > Polygon;
 
double cross(Vector a, Vector b)
{
  return (a.x * b.y - a.y * b.x);
}
 
int ccw(Point p0, Point p1, Point p2)
{
  Vector a = p1 - p0, b = p2 - p0;
  if(cross(a, b) < -EPS) return (-1);
  if(cross(a, b) > EPS) return (1);
  return (0);
}
 
struct Edge
{
  int a, b;
  double cost;
  bool operator < (const Edge d) const {
    return (cost < d.cost);
  }
};
 
struct Unionfind
{
  vector < int > parent;
 
  Unionfind() {}
  Unionfind(int sz) {
    for(int i = 0; i < sz; i++) {
      parent.push_back(i);
    }
  }
 
  bool unite(int a, int b)
  {
    a = getp(a); b = getp(b);
    if(a == b) return (false);
    parent[a] = b;
    return (true);
  }
 
  int getp(int n)
  {
    if(parent[n] == n) return (n);
    return (parent[n] = getp(parent[n]));
  }
};
 
Polygon AndrewScan(Polygon s);
double kruskal();
 
int n, m;
Polygon s;
vector < Edge > edges;
Unionfind tree;
 
map < Point, int > num;
 
main()
{
  double ans = 0.0;
   
  cin >> n >> m;
  for(int i = 0; i < n; i++) {
    Point p;
    p.input();
    s.push_back(p);
    num[s[i]] = i;
  }
   
  for(int i = 0; i < m; i++) {
    int a, b;
    cin >> a >> b; --a, --b;
    edges.push_back( (Edge) { a, b, (s[a] - s[b]).abs() } );
  }
   
  s = AndrewScan(s);
 
  tree = Unionfind(n);
  for(int i = 0; i < s.size(); i++) {
    tree.unite(num[s[i]], num[s[(i + 1) % s.size()]]);
    ans += (s[(i + 1) % s.size()] - s[i]).abs();
  }
  ans += kruskal();
 
  printf("%f\n", ans);
   
  return (0);
}
 
Polygon AndrewScan(Polygon s)
{
  Polygon u, l;
  int ssz = s.size();
 
  sort(s.begin(), s.end());
   
  u.push_back(s[0]); u.push_back(s[1]);
  l.push_back(s[ssz - 1]); l.push_back(s[ssz - 2]);
   
  for(int i = 2; i < ssz; i++) {
    int size = u.size();
    while(size >= 2 && ccw(u[size - 2], u[size - 1], s[i]) >= 0) {
      u.pop_back(); size--;
    }
    u.push_back(s[i]);
  }
   
  for(int i = ssz - 3; i >= 0; i--) {
    int size = l.size();
    while(size >= 2 && ccw(l[size - 2], l[size - 1], s[i]) >= 0) {
      l.pop_back(); size--;
    }
    l.push_back(s[i]);
  }
 
  for(int i = 1; i < l.size() - 1; i++) {
    u.push_back(l[i]);
  }
   
  return (u);
}
 
double kruskal()
{
  double sum = 0.0;
   
  sort(edges.begin(), edges.end());
 
  for(int i = 0; i < edges.size(); i++) {
    if(tree.unite(edges[i].a, edges[i].b)) {
      sum += edges[i].cost;
    }
  }
 
  return (sum);
}

Measured memory_bytes: 3256