#ifdef poe #define debug(x) cerr<<#x<<": "< using namespace std; using ll=long long; using ull=unsigned long long; using ld=long double; using pi=pair; using pll=pair; using str=string; templateusing vec=vector; using vi=vec;using vvi=vec;using vvvi=vec;using vvvvi=vec;using vvvvvi=vec; using vll=vec;using vvll=vec;using vvvll=vec;using vvvvll=vec;using vvvvvll=vec; using vpi=vec;using vvpi=vec;using vvvpi=vec;using vvvvpi=vec;using vvvvvpi=vec; using vpll=vec;using vvpll=vec;using vvvpll=vec;using vvvvpll=vec;using vvvvvpll=vec; templateusing pq=priority_queue>; templateusing pqg=priority_queue,greater>; #define rep(i,n) for(int i=0;i<(int)(n);i++) #define rep1(i,n) for(int i=1;i<=(int)(n);i++) #define per(i,n) for(int i=(int)(n)-1;0<=i;i--) #define per1(i,n) for(int i=(int)(n);0>(i))&1) #define pf push_front #define pb push_back #define df pop_front #define db pop_back #define fi first #define se second #define elif else if #define Yes cout<<"Yes"<<'\n' #define No cout<<"No"<<'\n' #define YN(x) cout<<((x)?"Yes":"No")<<'\n' #define O(x) cout<<(x)<<'\n' templatebool chmin(S&a,T b){if(a>b){a=b;return true;}return false;} templatebool chmax(S&a,T b){if(abool ismid(S a,S b,S c){return a<=b&&bbool next_combination(T l,T r,int k){T m=l+k;if(l==r||l==m||r==m)return false;T t=m;while(l!=t){t--;if(*t<*(r-1)){T d=m;while(*t>=*d)d++;iter_swap(t,d);rotate(t+1,d+1,r);rotate(m,m+(r-d)-1,r);return true;}}rotate(l,m,r);return false;} templateT Min(T a,T b){return aT Min(T a,T b,Args...args){return Min(Min(a,b),args...);} templateT Max(T a,T b){return a>b?a:b;} templateT Max(T a,T b,Args...args){return Max(Max(a,b),args...);} templateT Sum(T a){return a;} templateT Sum(T a,Args... args){return a+Sum(args...);} templateT Max(const vector&v){return *max_element(all(v));} templateT Min(const vector&v){return *min_element(all(v));} templateT Sum(const vector&v){return accumulate(all(v),T(0));} templateT Max(const pair&p){return max(p.first,p.second);} templateT Min(const pair&p){return min(p.first,p.second);} templateT Sum(const pair&p){return p.first+p.second;} templateistream&operator>>(istream&s,pair&p){s>>p.first>>p.second;return s;} templateostream&operator<<(ostream&s,pair&p){s<istream&operator>>(istream&s,vector&v){for(auto&i:v)s>>i;return s;} templateostream&operator<<(ostream&s,vector&v){for(auto&i:v)s<long long bsearch(long long ok,long long ng,F&f){while(abs(ok-ng)>1){long long mid=(ok+ng)/2;if(f(mid))ok=mid;else ng=mid;}return ok;} const int dxy[5]={0,1,0,-1,0}; const int dx[8]={0,1,0,-1,1,1,-1,-1}; const int dy[8]={1,0,-1,0,1,-1,1,-1}; #define nl '\n' #define sp ' ' #define inf ((1<<30)-(1<<15)) #define INF (1LL<<61) #define mod 998244353 void IO() { ios::sync_with_stdio(false); cin.tie(nullptr); cout< data; // _n 個の要素からなるUnionFind を構築 O(n) UnionFind(int n) : _n(n), data(n, -1) {} // 2 つの要素を併合 O(α(n)) bool merge(int p, int q) { p = root(p); q = root(q); if (p == q) return false; if (q < p) swap(p, q); data[p] += data[q]; data[q] = p; return true; } // 親要素を取得 O(α(n)) int root(int p) { assert(0 <= p && p < _n); if (data[p] < 0) { return p; } else { data[p] = root(data[p]); return data[p]; } } // 親要素を取得 O(α(n)) int operator[](int p) { return root(p); } // 2 つの要素が同じ集合に含まれるか判定 O(α(n)) bool same(int p, int q) { return root(p) == root(q); } // 要素が属する集合の大きさを返す O(α(n)) int size(int p) { return -data[root(p)]; } // UnionFind の連結成分のvector を返す O(n α(n)) vector> groups() { vector> re(_n); for (int i=0; i<_n; i++) re[root(i)].push_back(i); re.erase(remove_if(re.begin(), re.end(), [](vector& v){ return v.empty(); }), re.end()); return re; } }; int main() { IO(); int T=1; // cin >> T; while (T--) solve(); } ll dfs(int x, vvpll &g, vll& dp) { if (dp[x] != -1) return dp[x]; ll ans = 0; for (auto [y, w] : g[x]) { ans = max(ans, dfs(y, g, dp) + w); } return dp[x] = ans; } struct Edge { int u, v, w; bool operator<(const Edge& other) const { return w < other.w; } }; void solve() { int n, m; cin >> n >> m; vector edges(m); for (int i = 0; i < m; i++) { cin >> edges[i].u >> edges[i].v >> edges[i].w; edges[i].u--; edges[i].v--; } sort(edges.begin(), edges.end()); reverse(edges.begin(), edges.end()); UnionFind uf(n); ll ans=0; for (int i = 0; i < m; i++) { int u = edges[i].u; int v = edges[i].v; if (uf.root(u) != uf.root(v)) { uf.merge(u, v); ans += edges[i].w; } } cout << ans * 2 << nl; }