#include <bits/stdc++.h>

using namespace std;

#define REP(i, n) for (int i=0; i<(n); ++i)
#define RREP(i, n) for (int i=(int)(n)-1; i>=0; --i)
#define FOR(i, a, n) for (int i=(a); i<(n); ++i)
#define RFOR(i, a, n) for (int i=(int)(n)-1; i>=(a); --i)

#define SZ(x) ((int)(x).size())
#define all(x) begin(x),end(x)

#define dump(x) cerr<<#x<<" = "<<(x)<<endl
#define debug(x) cerr<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<<endl;

template<class T>
ostream &operator<<(ostream &os, const vector <T> &v) {
    os << "[";
    REP(i, SZ(v)) {
        if (i) os << ", ";
        os << v[i];
    }
    return os << "]";
}

template<class T, class U>
ostream &operator<<(ostream &os, const pair <T, U> &p) {
    return os << "(" << p.first << " " << p.second << ")";
}

template<class T>
bool chmax(T &a, const T &b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return true;
    }
    return false;
}

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<int, int>;
using vi = vector<int>;
using vll = vector<ll>;
using vvi = vector<vi>;
using vvll = vector<vll>;

const ll MOD = 1e9 + 7;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;
const ld EPS = 1e-9;

template<class T>
struct edge {
    int src, to;
    T cost;

    edge() {}

    edge(int to, T cost) : src(-1), to(to), cost(cost) {}

    edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}

    friend ostream &operator<<(ostream &os, const edge &e) {
        return os << "(" << e.src << "->" << e.to << ":" << e.cost << ")";
    }
};

struct UnionFind
{
    vector<int> par, sz;
    const int n;
    UnionFind(int n) : n(n), par(n), sz(n, 1) {
        for (int i = 0; i < n; ++i) par[i] = i;
    }

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

    void merge(int x, int y) {
        x = root(x);
        y = root(y);
        if (x == y) return;
        if (sz[x] < sz[y]) swap(x, y);
        par[y] = x;
        sz[x] += sz[y];
        sz[y] = 0;
    }

    bool issame(int x, int y) {
        return root(x) == root(y);
    }

    int size(int x) {
        return sz[root(x)];
    }

    friend ostream& operator<<(ostream& os, UnionFind& uf) {
        os << "[";
        for (int i = 0; i < uf.n; ++i) {
            if (i > 0) os << " ";
            os << uf.root(i);
        }
        return os << "]" << endl;
    }
};


template<typename T>
T kruskal(const vector<edge<T>> &es, int V) {

    UnionFind uf(V);
    T ret = 0;

    vector<int> ord(es.size());
    iota(ord.begin(), ord.end(), 0);
    sort(ord.begin(), ord.end(), [&](int i,int j){
        return es[i].cost > es[j].cost;
    });

    for (auto i : ord) {
        auto &e = es[i];
        if (!uf.issame(e.src, e.to)) {
            ret += e.cost;
            uf.merge(e.src, e.to);
        }
    }

    return ret;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);

    int n, m; cin >> n >> m;
    vector<complex<double>> p(n);
    REP(i, n)  {
        double x, y; cin >> x >> y;
        p[i] = { x, y };
    }

    vector<edge<double>> edges(m);
    REP(i, m) {
        int u, v; cin >> u >> v; --u, --v;
        edges[i] = { u, v, abs(p[u] - p[v]) };
    }

    double sum = 0;
    REP(i, m) sum += edges[i].cost;

    sum -= kruskal(edges, n);
    cout << sum << endl;

    return 0;
}



Measured memory_bytes: 4028