#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
struct edge {
    int to;
    double cost;
};
const int MAX_N = 10005;
int N, M;
int X[MAX_N], Y[MAX_N];
double d[MAX_N];
bool used[MAX_N];
vector<edge> G[MAX_N];

//2点間の距離を返す
double dist(int a, int b) {
    unsigned int num = (X[a]-X[b]) * (X[a]-X[b]) + (Y[a]-Y[b])*(Y[a]-Y[b]);
    double ret = sqrt(num);
    return ret;
}

int main(int argc, const char * argv[])
{
    scanf("%d %d", &N, &M);
    for (int i = 0; i < N; i++) {
        scanf("%d %d", &X[i], &Y[i]);
    }
    double ret = 0;
    for (int i = 0; i < M; i++) {
        int a,b;
        scanf("%d %d", &a, &b);
        a--; b--;
        double d = dist(a, b);
        //printf("%d-%d:%f\n",a,b,d);
        ret += d;
        edge e1, e2;
        e1.to = b;
        e2.to = a;
        e1.cost = e2.cost = -d;  //負にすることで最大全域木を計算
        G[a].push_back(e1);
        G[b].push_back(e2);
    }
    for (int i = 0; i < N; i++) d[i] = 0;
    fill(used, used+N, false);
    //プリム法
    while (true) {
        int v = -1;
        for (int i = 0; i < N; i++) {
            if (!used[i] && (v == -1 || d[v] > d[i])) v = i;
        }
        if (v == -1) break;
        //頂点vを集合xに加える
        used[v] = true;
        ret += v[d];
        //集合xまでの最短距離を更新
        for (int i = 0; i < (int)G[v].size(); i++) {
            edge e = G[v][i];
            if (d[e.to] > e.cost) {
                d[e.to] = e.cost;
            }
        }
    }
    printf("%.3f\n", ret);
    return 0;
}