#include<bits/stdc++.h>
#define int long long
#define read read()
#define V e[i].v
#define X E[i].x
#define Y E[i].y
#define D E[i].d
#define ls (u<<1)
#define rs (u<<1|1)
#define lson ls,l,mid
#define rson rs,mid+1,r
#define mid ((l+r)>>1)
#define len (r-l+1)
#define inf 0xFFFFFFFFFFFFFFF
#define N 10000005
using namespace std;
struct Edge
{
int v;
int next;
}e[N<<1];
struct edge
{
int x;
int y;
int f;
int d;
bool operator < (const edge &T) const
{
return d<T.d;
}
}E[N<<1];
struct Node
{
int m1;
int m2;
}T,tree[N];
int n,m,r,p,x,y,z,W,tot,sum,num,cnt,ans=inf,head[N],v[N],w[N],F[N],ord[N];
int DFN,SIZE[N],depth[N],f[N],rem[N],dfn[N],top[N];
inline char C()
{
static char o[100000],*p=o,*P=o;
return p==P&&(P=(p=o)+fread(o,1,100000,stdin),p==P)?EOF:*p++;
}
inline int read
{
char c=C(); int t=1,s=0;
while((c<48||c>57)&&c!='-') c=C();
if(c=='-') t=-1,c=C();
while(c>47&&c<58) s=s*10+c-48,c=C();
return s*t;
}
int find(int k)
{
if(F[k]==k) return k;
return F[k]=find(F[k]);
}
inline void add(int u,int v)
{
e[++cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt;
}
void Kruskal()
{
num=n;
int res=1;
sort(E+1,E+m+1);
for(int i=1;i<=m&&res<n;i++)
{
if(find(X)!=find(Y))
{
F[find(X)]=find(Y);
add(X,++num),add(num,X);
add(Y,num),add(num,Y);
w[num]=D,sum+=D,res++;
E[i].f=1;
}
}
}
inline Node getmax(Node a,Node b)
{
Node res;
int T[5]={0,a.m1,a.m2,b.m1,b.m2},t=4;
sort(T+1,T+5),res.m1=T[4];
while(T[t]==T[4]) t--;
res.m2=T[t];
return res;
}
inline void push_up(int u)
{
tree[u]=getmax(tree[ls],tree[rs]);
}
void dfs1(int u,int fa)
{
int MAX=0;
f[u]=fa,SIZE[u]=1;
depth[u]=depth[fa]+1;
for(int i=head[u];i;i=e[i].next)
{
if(V==fa) continue;
dfs1(V,u),SIZE[u]+=SIZE[V];
if(SIZE[V]>MAX) MAX=SIZE[V],rem[u]=V;
}
}
void dfs2(int u,int fa)
{
top[u]=(rem[fa]==u?top[fa]:u);
dfn[u]=++DFN,ord[DFN]=u,v[DFN]=w[u];
if(rem[u]) dfs2(rem[u],u);
for(int i=head[u];i;i=e[i].next)
{
if(V!=fa&&V!=rem[u])
{
dfs2(V,u);
}
}
}
void build(int u,int l,int r)
{
if(l==r)
{
tree[u].m1=v[r];
tree[u].m2=0;
return;
}
build(lson);
build(rson);
push_up(u);
}
Node query(int u,int l,int r,int x,int y)
{
Node res=(Node){0,0};
if(x<=l&&r<=y) return tree[u];
if(x<=mid) res=getmax(res,query(lson,x,y));
if(y>mid) res=getmax(res,query(rson,x,y));
return res;
}
inline Node Query(int x,int y)
{
Node ans=(Node){0,0};
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]]) swap(x,y);
ans=getmax(ans,query(1,1,num,dfn[top[x]],dfn[x]));
x=f[top[x]];
}
if(depth[x]>depth[y]) swap(x,y);
ans=getmax(ans,query(1,1,num,dfn[x],dfn[y]));
return ans;
}
signed main()
{
n=read,m=read;
for(int i=1;i<=n;i++) F[i]=i;
for(int i=1;i<=m;i++) E[i].x=read,E[i].y=read,E[i].d=read;
Kruskal();
dfs1(1,0);
dfs2(1,0);
build(1,1,num);
for(int i=1;i<=m;i++)
{
if(E[i].f) continue;
W=E[i].d,T=Query(X,Y);
ans=min(ans,sum-(T.m1==W?T.m2:T.m1)+W);
}
printf("%lld",ans);
return 0;
}