#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long max(const long long &x,const long long &y){
return x>y?x:y;
}
long long min(const long long &x,const long long &y){
return x<y?x:y;
}
struct rec{
long long d;
int e,nex,s;
}z[2000010];
int en,fi[1000010];
void add(int s,int e,long long d){
++en;
z[en].e=e;
z[en].d=d;
z[en].nex=fi[s];
z[en].s=s;
fi[s]=en;
}
struct pai{
int s,e;
long long d;
}b[2000001];
int vis1[1000010];
bool cmp(pai x,pai y){
return x.d<y.d;
}
int son[1000010],fa[1000010],deep[1000010],top[1000010],siz[1000010],id[1000010],cnt;
bool vis[1000010];
long long a[1000010];
void dfs1(int x,int f){
deep[x]=deep[f]+1;
fa[x]=f;
siz[x]=1;
for (int i=fi[x];i!=0;i=z[i].nex){
if (vis[i]==false) continue;
if (deep[z[i].e]==0){
dfs1(z[i].e,x);
a[z[i].e]=z[i].d;
siz[x]+=siz[z[i].e];
if (siz[z[i].e]>siz[son[x]]) son[x]=z[i].e;
}
}
}
void dfs2(int x,int topp){
++cnt;
id[x]=cnt;
top[x]=topp;
if (son[x]==0) return ;
dfs2(son[x],topp);
for (int i=fi[x];i!=0;i=z[i].nex){
if (vis[i]==false) continue;
if (z[i].e!=son[x]&&z[i].e!=fa[x]) dfs2(z[i].e,z[i].e);
}
}
long long sum,ans;
struct trees{
int l,r;
long long maxn,cmaxn;
}tree[2000010];
void pushup(int i){
tree[i].maxn=max(tree[i*2].maxn,tree[i*2+1].maxn);
if (tree[i*2].maxn>tree[i*2+1].maxn){
tree[i].cmaxn=max(tree[i*2+1].maxn,tree[i*2].cmaxn);
}
else if (tree[i*2].maxn<tree[i*2+1].maxn){
tree[i].cmaxn=max(tree[i*2+1].cmaxn,tree[i*2].maxn);
}
else tree[i].cmaxn=max(tree[i*2].cmaxn,tree[i*2+1].cmaxn);
}
void build(int i,int l,int r){
tree[i].l=l;
tree[i].r=r;
if (l==r) {
tree[i].maxn=a[id[l]];
tree[i].cmaxn=-1e18;
return ;
}
int mid=(l+r)/2;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
pushup(i);
return ;
}
void query_maxn(int i,int l,int r,long long int d){
if (tree[i].l>=l&&tree[i].r<=r){
if (tree[i].maxn<d){
ans=min(ans,sum+d-tree[i].maxn);
return ;
}
if (tree[i].cmaxn==-1e18){
return ;
}
if (tree[i].maxn>=d&&tree[i].cmaxn<d){
ans=min(ans,sum+d-tree[i].cmaxn);
return ;
}
query_maxn(i*2,l,r,d);
query_maxn(i*2+1,l,r,d);
return ;
}
if (tree[i].l>r||tree[i].r<l) return ;
if (tree[i*2].r>=l) query_maxn(i*2,l,r,d);
if (tree[i*2+1].l<=r) query_maxn(i*2+1,l,r,d);
return ;
}
int n,m;
int ff[1000010];
int get(int x){
if (ff[x]==x) return x;
return ff[x]=get(ff[x]);
}
void query(int x,int y){
ff[get(x)]=get(y);
}
bool cmpp(int x,int y){
return get(x)==get(y);
}
void qmaxn(int x,int y,long long d){
while (top[x]!=top[y]){
if (deep[top[x]]<deep[top[y]]) swap(x,y);
query_maxn(1,id[top[x]],id[x],d);
x=fa[top[x]];
}
if (x==y) return ;
query_maxn(1,min(id[x],id[y])+1,max(id[x],id[y]),d);
return ;
}
void check(){
printf("fa:");
for (int i=1;i<=n;i++){
printf("%d ",fa[i]);
}
printf("\n");
printf("deep:");
for (int i=1;i<=n;i++){
printf("%d ",deep[i]);
}
printf("\n");
printf("siz:");
for (int i=1;i<=n;i++){
printf("%d ",siz[i]);
}
printf("\n");
printf("topp:");
for (int i=1;i<=n;i++){
printf("%d ",top[i]);
}
printf("\n");
printf("id:");
for (int i=1;i<=n;i++){
printf("%d ",id[i]);
}
printf("\n");
printf("son:");
for (int i=1;i<=n;i++){
printf("%d ",son[i]);
}
printf("\n");
printf("a:");
for (int i=1;i<=n;i++){
printf("%lld ",a[i]);
}
printf("\n");
printf("Ñ¡±ß:\n");
for (int i=2;i<=en;i+=2){
if (vis[i]==true){
printf("%d %d %d\n",z[i].s,z[i].e,z[i].d);
}
}
printf("δѡ±ß:\n");
for (int i=2;i<=en;i+=2){
if (vis[i]==false) printf("%d %d %d\n",z[i].s,z[i].e,z[i].d);
}
}
int main(){
en=1;
for (int i=1;i<=1000000;i++) ff[i]=i;
scanf("%d%d",&n,&m);
int m1=0;
for (int i=1;i<=m;i++){
int s,e;
long long d;
scanf("%d%d%lld",&s,&e,&d);
if (s!=e){
++m1;
b[m1].s=s;
b[m1].e=e;
b[m1].d=d;
}
}
sort(b+1,b+m1+1,cmp);
for (int i=1;i<=m1;i++){
if (cmpp(b[i].s,b[i].e)==false){
query(b[i].s,b[i].e);
sum+=b[i].d;
vis1[i]=true;
}
}
for (int i=1;i<=m1;i++){
add(b[i].s,b[i].e,b[i].d);
vis[en]=vis1[i];
add(b[i].e,b[i].s,b[i].d);
vis[en]=vis1[i];
}
ans=1e18;
dfs1(1,0);
dfs2(1,1);
a[1]=-1e18;
build(1,1,n);
for (int i=2;i<=en;i+=2){
if (vis[i]==true) continue;
qmaxn(z[i].s,z[i].e,z[i].d);
}
printf("%lld",ans);
return 0;
}