#include <iostream>
#include <complex>
#include <utility>
#include <algorithm>
#include <vector>
#include <tuple>
#include <map>
using namespace std;

typedef complex<double> Point, Vector;
typedef vector<Point> Polygon;

#define X real()
#define Y imag()
#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)

namespace std{
    bool operator<(const Point &a, const Point &b){
        return !equals(a.X, b.X) ? a.X < b.X : a.Y < b.Y;
    }
}

double dot(Vector a, Vector b){
    return a.X * b.X + a.Y * b.Y;
}

double cross(Vector a, Vector b){
    return a.X * b.Y - a.Y * b.X;
}

double norm(Vector a){
    return a.X * a.X + a.Y * a.Y;
}

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

int ccw(Point p0, Point p1, Point p2){
    Vector a = p1 - p0;
    Vector b = p2 - p0;
    if(cross(a, b) > EPS) return 1;
    if(cross(a, b) < -EPS) return -1;
    if(dot(a, b) < -EPS) return 2;
    if(norm(a) < norm(b)) return -2;

    return 0;
}

Polygon convexHull(Polygon ps){
    int n = ps.size();
    sort(ps.begin(), ps.end());
    int k = 0;
    Polygon convex(n * 2);
    for(int i=0; i<n; i++){
        while(k >= 2 && ccw(convex[k-2], convex[k-1], ps[i]) == -1) k--;
        convex[k++] = ps[i];
    }
    for(int i=n-2, t=k; i>=0; i--){
        while(k > t && ccw(convex[k-2], convex[k-1], ps[i]) == -1) k--;
        convex[k++] = ps[i];
    }
    convex.resize(k-1);
    return convex;
}

struct UnionFind{
    vector<int> par;
    vector<int> ranks;
    vector<int> size;

private:
    void init(int n = 1){
        par.resize(n);
        ranks.resize(n);
        size.resize(n);
        for(int i=0; i<n; i++){
            par[i] = i;
            ranks[i] = 0;
            size[i] = 1;
        }
    }

public:
    UnionFind(int n = 1){
        init(n);
    }

    int find(int x){
        if(par[x] == x) return x;
        else return par[x] = find(par[x]);
    }

    bool same(int x, int y){
        return find(x) == find(y);
    }

    void unite(int x, int y){
        x = find(x);
        y = find(y);
        if(x == y) return ;
        if(ranks[x] < ranks[y]) swap(x, y);
        if(ranks[x] == ranks[y]) ranks[x]++;
        par[y] = x;
        size[x] += size[y];
        return ;
    }
};

int main(){
    int v, r; cin>>v>>r;
    UnionFind uf(v);
    Polygon pol;
    vector<int> x(v), y(v);
    for(int i=0; i<v; i++){
        cin>>x[i]>>y[i];
        pol.emplace_back(x[i], y[i]);
    }

    pol = convexHull(pol);

    int n = pol.size();
    double ans = 0;
    for(int i=0; i<n; i++){
        double cdist = abs(pol[(i+1)%n] - pol[i]);
        ans += cdist;
        int cur, nxt;
        for(int j=0; j<v; j++){
            if(x[j] == pol[i].X && y[j] == pol[i].Y) cur = j;
            if(x[j] == pol[(i+1)%n].X && y[j] == pol[(i+1)%n].Y) nxt = j;
        }

        uf.unite(cur, nxt);
    }
    
    vector<tuple<double, int, int>> edge;
    for(int i=0; i<r; i++){
        int s, t; cin>>s>>t;
        s--, t--;
        double cdist = sqrt(abs(x[s] - x[t]) * abs(x[s] - x[t]) + abs(y[s] - y[t]) * abs(y[s] - y[t]));
        edge.emplace_back(cdist, s, t);
    }

    sort(edge.begin(), edge.end());

    for(int i=0; i<r; i++){
        double cdist; int s, t;
        tie(cdist, s, t) = edge[i];

        if(uf.same(s, t)) continue;
        uf.unite(s, t);
        ans += cdist;
    }

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


Measured memory_bytes: 3256