#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <functional>
#include <bitset>

using namespace std;

using Real = double;
using Point = complex<Real>;
using Polygon = vector<Point>;
const Real EPS = 1e-8, PI = acos(-1);

inline bool eq(const Real a, const Real b){return fabs(b-a) < EPS; }

namespace std{
    bool operator==(const Point &a, const Point &b){
        return eq(a.real(), b.real()) && eq(a.imag(), b.imag());
    }
    bool operator<(const Point &a, const Point &b){
        return !eq(a.real(), b.real()) ? a.real() < b.real() : a.imag() < b.imag();
    }
}


Point operator*(const Point &p, const Real &d){
    return Point(real(p) * d, imag(p) * d);
}

Real cross(const Point &a, const Point &b){
    return real(a) * imag(b) - imag(a) * real(b);
}

Real dot(const Point &a, const Point &b){
    return real(a) * real(b) + imag(a) * imag(b);
}

int ccw(const Point &a, Point b, Point c){
    b = b-a, c = c-a;
    if(cross(b,c) > EPS) return +1;
    if(cross(b,c) < -EPS) return -1;
    if(dot(b,c) < 0) return +2;
    if(norm(b) < norm(c)) return -2;
    return 0;
}

bool is_convex(const Polygon &p){
    int n = (int)p.size();
    for(int i = 0; i < n; i++){
        if(ccw(p[(i+n-1)%n], p[i], p[(i+1)%n]) == -1) return false;
    }
    return true;
}

Polygon convex_hull(Polygon &p){
    int n = (int)p.size(), k = 0;
    if(n <= 2)return p;
    sort(p.begin(), p.end());
    vector<Point> ch(2*n);
    for(int i = 0; i < n; ch[k++] = p[i++]){
        while(k >= 2 && cross(ch[k-1] - ch[k-2], p[i] - ch[k-1]) < 0) --k;
    }

    for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]){
        while(k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0) --k;
    }
    ch.resize(k-1);
    return ch;
}

template<typename T>
T prim(vector<vector<pair<int, T>>> &g){
    int n = (int)g.size();
    T ret = 0;
    vector<bool> used(n, false);
    using P = pair<T, int>;
    priority_queue<P, vector<P>, greater<P>> que;
    que.push({0, 0});
    while(!que.empty()){
        auto p = que.top();
        que.pop();
        if(used[p.second]) continue;
        used[p.second] = true;
        ret += p.first;
        for(auto & e : g[p.second]){
            que.push({e.second, e.first});
        }
    }

    return ret;
}

signed main(){
    int V,R; cin >> V >> R;
    vector<Point> p(V);
    map<Point, int> toNode;
    map<int, Point> toPoint;

    int val = 0;
    for(auto &e : p){
        Real a,b; cin >> a >> b;
        toNode[Point(a, b)] = val;
        toPoint[val] = Point(a, b);
        e = Point(a,b);
        val++;
    }
       
    set<Point> isHull;
    auto hull = convex_hull(p);
    for(auto x : hull){
        isHull.insert(x);
    }
    
    vector<vector<pair<int, double>>> g(V);
    for(int i = 0; i < R; i++){
        int s, t; cin >> s >> t;
        s--;
        t--;
        Point pa = toPoint[s];
        Point pb = toPoint[t];
        double cost = abs(pa - pb);
        if(isHull.find(pa) != isHull.end() && isHull.find(pb) != isHull.end()) cost = 0.0;
        //cout << " from " << pa.real() << " " << pa.imag() << "    to   " <<  pb.real() << " " << pb.imag() << "    cost :  " << cost << endl;
        g[s].push_back({t, cost});
        g[t].push_back({s, cost});
    }

    for(int i = 0; i < (int)hull.size(); i++){
        
        Point a = hull[i];
        Point b = hull[(i + 1) % hull.size()];
        int idxa = toNode[a];
        int idxb = toNode[b];
        g[idxa].push_back({idxb, 0.0});
        g[idxb].push_back({idxa, 0.0});

    }
    
    double ans = prim(g);
    //cout << ans << endl;
    for(int i = 0; i < (int)hull.size(); i++){
        Point a = hull[i];
        Point b = hull[(i + 1) % hull.size()];
        ans += abs(a - b);
    }
    
    printf("%.10f\n", ans);
    return 0;
}



Measured memory_bytes: 3348