// kruskal 贪心思想 并查集
#include <bits/stdc++.h>
using namespace std;
// 将所有边按照权重从小到大排序
// 遍历所有边,如果两点可以合并,进入mst(最小生成树)集
int n, m, p, u, v, w, t = 0, ans = 0;
struct edge
{
int p, u, v, w;
bool operator<(const edge &b) const
{
if (p == b.p)
return w < b.w;
return p < b.p;
}
} e[10050];
int fat[2005];
void init()
{
for (int i = 0; i < 2005; i++)
fat[i] = i;
}
int findfat(int x)
{
if (fat[x] != x)
fat[x] = findfat(fat[x]); // 路径压缩
return fat[x];
}
void uset(int a, int b)
{
int fa = findfat(a);
int fb = findfat(b);
if (fa != fb)
fat[fb] = fa;
}
void kruskal()
{
sort(e, e + t);
int nn = 0;
for (int i = 0; i < t; i++)
{
int u = e[i].u, v = e[i].v;
if (e[i].p == 1 || findfat(u) != findfat(v))
{
uset(u, v);
ans += e[i].w;
// cout<<e[i].w<<" ";
nn++;
}
}
}
int main()
{
cin >> n >> m;
while (m--)
{
cin >> p >> u >> v >> w;
e[t++] = {p, u, v, w};
}
init();
kruskal();
cout << ans;
return 0;
}