Problem:
Minimum Spanning Tree
Find the sum of weights of edges of the Minimum Spanning Tree for a given weighted undirected graph
G
= (
V
,
E
).
Input
|V|
|E|
s
0
t
0
w
0
s
1
t
1
w
1
:
s
|E|-1
t
|E|-1
w
|E|-1
, where
|V|
is the number of vertices and
|E|
is the number of edges in the graph. The graph vertices are named with the numbers 0, 1,...,
|V|
-1 respectively.
s
i
and
t
i
represent source and target verticess of
i
-th edge (undirected) and
w
i
represents the weight of the
i
-th edge.
Output
Print the sum of the weights of the Minimum Spanning Tree.
Constraints
1 ≤
|V|
≤ 10,000
0 ≤
|E|
≤ 100,000
0 ≤
w
i
≤ 10,000
The graph is connected
There are no parallel edges
There are no self-loops
Sample Input 1
4 6
0 1 2
1 2 1
2 3 1
3 0 1
0 2 3
1 3 5
Sample Output 1
3
Sample Input 2
6 9
0 1 1
0 2 3
1 2 1
1 3 7
2 4 1
1 4 3
3 4 1
3 5 1
4 5 6
Sample Output 2
5

Submitted solutions:

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int MAX_WEIGHT = 10000;

struct Node
{
    vector<pair<int, int>> children; // destination node, weight
};

void tmp(const vector<Node> &nodes, vector<int> &weights, int current)
{
    for (pair<int, int> p : nodes[current].children)
    {
        int d = p.first;
        int w = p.second;

        if (w < weights[d])
        {
            weights[d] = w;
            tmp(nodes, weights, d);
        }
    }
}

int main()
{
    int vertexN, edgeN;
    cin >> vertexN >> edgeN;

    vector<Node> nodes(vertexN);
    for (int i = 0; i < edgeN; i++)
    {
        int s, t, w;
        cin >> s >> t >> w;
        nodes[s].children.emplace_back(t, w);
        nodes[t].children.emplace_back(s, w);
    }

    vector<int> weights(vertexN, MAX_WEIGHT);
    weights[0] = 0;
    tmp(nodes, weights, 0);

    int sum = 0;
    for (int w : weights)
    {
        sum += w;
    }
    cout << sum << endl;
}

// 各点から最短距離を求め続ける、始点から始める
// 未探索 or 最短になる場合はその点にアクセス
// アクセスした点から別の点にアクセス、これを繰り返す
// 未探索の点がある場合はその点から最短距離を求める
// ↑ここ要修正
// なんか似たことやったことある気がするなぁ
accuracy: 0.25
time_ms: 30
memory_kb: 4840
final_rank: 20

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int MAX_WEIGHT = 10000;

struct Node
{
    vector<pair<int, int>> children; // destination node, weight
};

void tmp(const vector<Node> &nodes, vector<int> &weights, int current)
{
    for (pair<int, int> p : nodes[current].children)
    {
        int d = p.first;
        int w = p.second;

        if (w < weights[d])
        {
            weights[d] = w;
            tmp(nodes, weights, d);
        }
    }
}

int main()
{
    int vertexN, edgeN;
    cin >> vertexN >> edgeN;

    vector<Node> nodes(vertexN);
    for (int i = 0; i < edgeN; i++)
    {
        int s, t, w;
        cin >> s >> t >> w;
        nodes[s].children.emplace_back(t, w);
        nodes[t].children.emplace_back(s, w);
    }

    vector<int> weights(vertexN, MAX_WEIGHT);
    weights[0] = 0;
    tmp(nodes, weights, 0);
    for (int i = 1; i < vertexN; i++)
    {
        if (weights[i] == MAX_WEIGHT)
        {
            tmp(nodes, weights, i);
        }
    }

    int sum = 0;
    for (int w : weights)
    {
        sum += w;
    }
    cout << sum << endl;
}

// 各点から最短距離を求め続ける、始点から始める
// 未探索 or 最短になる場合はその点にアクセス
// アクセスした点から別の点にアクセス、これを繰り返す
// 未探索の点がある場合はその点から最短距離を求める
// ↑ここ要修正
// なんか似たことやったことある気がするなぁ
accuracy: 0.25
time_ms: 30
memory_kb: 4748
final_rank: 19

code_snippet: #include <bits/stdc++.h>
#pragma GCC target("avx2")
#ifndef LOCAL
#pragma GCC optimize("O3")
#endif
#pragma GCC optimize("unroll-loops")

/// @brief Union-Find 木
/// @note 1.4 高速化 + 省メモリ化
/// @see https://zenn.dev/reputeless/books/standard-cpp-for-competitive-programming/viewer/union-find
class UnionFind
{
public:

	UnionFind() = default;

	/// @brief Union-Find 木を構築します。
	/// @param n 要素数
	explicit UnionFind(size_t n)
		: m_parentsOrSize(n, -1) {}

	/// @brief 頂点 i の root のインデックスを返します。
	/// @param i 調べる頂点のインデックス
	/// @return 頂点 i の root のインデックス
	int find(int i)
	{
		if (m_parentsOrSize[i] < 0)
		{
			return i;
		}

		// 経路圧縮
		return (m_parentsOrSize[i] = find(m_parentsOrSize[i]));
	}

	/// @brief a のグループと b のグループを統合します。
	/// @param a 一方のインデックス
	/// @param b 他方のインデックス
	void merge(int a, int b)
	{
		a = find(a);
		b = find(b);

		if (a != b)
		{
			// union by size (小さいほうが子になる）
			if (-m_parentsOrSize[a] < -m_parentsOrSize[b])
			{
				std::swap(a, b);
			}

			m_parentsOrSize[a] += m_parentsOrSize[b];
			m_parentsOrSize[b] = a;
		}
	}

	/// @brief a と b が同じグループに属すかを返します。
	/// @param a 一方のインデックス
	/// @param b 他方のインデックス
	/// @return a と b が同じグループに属す場合 true, それ以外の場合は false
	bool connected(int a, int b)
	{
		return (find(a) == find(b));
	}

	/// @brief i が属するグループの要素数を返します。
	/// @param i インデックス
	/// @return i が属するグループの要素数
	int size(int i)
	{
		return -m_parentsOrSize[find(i)];
	}

private:

	// m_parentsOrSize[i] は i の 親,
	// ただし root の場合は (-1 * そのグループに属する要素数)
	std::vector<int> m_parentsOrSize;
};

#ifdef ONLINE_JUDGE
#include <atcoder/all>
#include <boost/multiprecision/cpp_int.hpp>
#endif
#ifdef LOCAL
#define GLIBCXX_DEBUG
#else
#define endl "\n"
#endif
using namespace std;using ll=long long;using ull=unsigned long long;using dl=long double;
#define rep(i,n) for(ll i=0; i<(n); i++)
#define rrep(i,n) for(ll i=1; i<=(n); i++)
#define drep(i,n) for(ll i=(n)-1; i>=0; i--)
#define xfor(i,s,e) for(ll i=(s); i<(e); i++)
#define rxfor(i,s,e) for(ll i=(s); i<=(e); i++)
#define dfor(i,s,e) for(ll i=(s)-1; i>=(e); i--)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define chmax(x,y) x = max((x),(y))
#define chmin(x,y) x = min((x),(y))
#define popcnt(s) ll(__popcount<ull>(uint64_t(s)))
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(auto&in:v)is>>in;return is;}
template<typename T, typename U>ostream&operator<<(ostream&os,const pair<T,U>&v){os<<v.first<<" "<<v.second;return os;}
template<typename T>ostream&operator<<(ostream&os,const vector<T>&v){for(auto&in:v)os<<in<<' ';return os;}
template<typename T>ostream&operator<<(ostream&os,const vector<vector<T>>&v){for(auto&in:v)os<<in<<endl;return os;}
ll modpow(ll a, ll b, ll mod) {ll res = 1;while (b > 0) {if (b & 1) res = (res * a) % mod;a = (a * a) % mod;b >>= 1;}return res;}
ll powl(ll a, ll b) {ll res = 1;while (b > 0) {if (b & 1) res = (res * a);a = (a * a);b >>= 1;}return res;}
#define pow2(a) (a)*(a)
/*MOD MUST BE A PRIME NUMBER!!*/ll moddiv(const ll a, const ll b, const ll mod) {ll modinv = modpow(b, mod-2, mod);return (a * modinv) % mod;}
const ll INF = 2e15;
ll nC2(const ll i){return i>2?i*(i-1)/2:0;}ll nC3(const ll i){return i>3?i*(i-1)*(i-2)/6:0;}ll nC4(const ll i){return i>4?i*(i-1)*(i-2)*(i-3)/24:0;}ll nC5(const ll i){return i>5?i*(i-1)*(i-2)*(i-3)*(i-4)/120:0;}ll nC6(const ll i){return i>6?i*(i-1)*(i-2)*(i-3)*(i-4)*(i-5)/720:0;}
void warshall_floyd(vector<vector<ll>>& dist) {const ull n = dist.size();rep(k, n) rep(i, n) rep(j, n) {dist[i][j] = min(dist[i][j],dist[i][k] + dist[k][j]);}}
#define YES {cout<<"Yes\n";return;}
#define NO {cout<<"No\n";return;}
#define yn YES else NO
#ifdef ONLINE_JUDGE
using lll = boost::multiprecision::cpp_int;
//using lll = boost::multiprecision::int128_t;
using namespace atcoder;
//using mint = modint1000000007;
using mint = modint998244353;
//using mint = modint; // custom mod
//atcoder::modint::set_mod(m);
// DSU == UnionFind
#endif
#define vc vector
using P = pair<ll, ll>;using vl = vc<ll>;using vb=vc<bool>;using vs=vc<string>;using vvl=vc<vl>;using vp=vc<P>;
#define pq priority_queue
template<typename T>void cs(vector<T>&v){xfor(i,1,v.size())v[i]+=v[i-1];}

vl dx = {-1, 1, 0, 0, -1, 1, -1, 1};
vl dy = {0, 0, 1, -1, -1, -1, 1, 1};

const ll mod = 998244353;

void solve() {
    ll V, E;
    cin >> V >> E;
    
    pq<tuple<ll,ll,ll>, vector<tuple<ll,ll,ll>>, greater<>> q;
    rep(i, E) {
        ll s, t, w;
        cin >> s >> t >> w;
        q.emplace(w, s, t);
    }

    UnionFind tree(V);

    ll res = 0;
    while (!q.empty()) {
        auto [w,s,t] = q.top(); q.pop();
        if (!tree.connected(s,t)) {
            tree.merge(s,t);
            res += w;
        }
    }

    cout << res << endl;
}

int main() {
    ios_base::sync_with_stdio(false);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cout << fixed << setprecision(50);

    ll n = 1;
    //cin >> n;
    while (n--) {
        solve();
    }
}
accuracy: 1
time_ms: 20
memory_kb: 7660
final_rank: 2

code_snippet: #include <bits/stdc++.h>

using namespace std;
// #include "all.h"

#define int long long
#define uint unsigned int
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define is2pow(n) (n && (!(n & (n - 1))))
#define OPTIMIZE                                                                                                       \
    ios_base::sync_with_stdio(false);                                                                                  \
    cin.tie(nullptr);                                                                                                  \
    cout.tie(nullptr);

using ld = long double;
constexpr int maxn = 2e5;
constexpr int maxk = 305;
constexpr long long inf = 1e18;
constexpr ld eps = 1e-8L;
constexpr long long mod = 998244353;


struct DSU {
    vector<int> parent;
    vector<int> rank;

    DSU(int n) : parent(n), rank(n,0) {
        iota(all(parent),0);
    }

    int find_set(int u) {
        if (u==parent[u]) return u;
        return parent[u] = find_set(parent[u]);
    }

    void union_set(int u, int v) {
        u = find_set(u);
        v = find_set(v);
        if (u==v) return;
        if (rank[u] < rank[v]) swap(u, v);
        parent[v] = u;
        if (rank[u] == rank[v]) rank[u]++;
    }
};


struct Edge {
    int from,to,weight;
    Edge(int from, int to, int weight) : from(from), to(to), weight(weight) {}

    bool operator<(const Edge& e) const {
        return weight < e.weight;
    }
};

vector<Edge> edges;

void solve() {
    int n,m; cin >> n >> m;
    DSU dsu(n);
    for (int i = 0; i < m; i++) {
        int u,v,w; cin >> u >> v >> w;
        edges.emplace_back(u,v,w);
    }
    sort(all(edges));
    int res= 0;
    for (auto& edge : edges) {
        auto [from,to,weight] = edge;
        if (dsu.find_set(from) != dsu.find_set(to)) {
            dsu.union_set(from,to);
            res+=weight;
        }
    }
    cout << res <<"\n";
}

#define TES
#define LOCA
#define FIL

int32_t main() {
    OPTIMIZE;

#ifdef FILE
    freopen("coins.in", "r", stdin);
    freopen("coins.out", "w", stdout);
#endif
#ifdef LOCAL
    freopen("/home/sq/CLionProjects/graph/input.txt", "r", stdin);
#endif
    int tt = 1;
#ifdef TEST
    cin >> tt;
#endif
    while (tt--) {
        solve();
    }
}
accuracy: 1
time_ms: 20
memory_kb: 7784
final_rank: 3

code_snippet: #include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>

struct Edge {
  int weight;
  int endA;
  int endB;
  Edge(int w, int a, int b) : weight(w), endA(a), endB(b) {}
};

int main() {
  int V, E;
  std::cin >> V >> E;
  std::vector<Edge> G;
  for (int i = 0; i < E; ++i) {
    int s, t, w;
    std::cin >> s >> t >> w;
    G.emplace_back(w, s, t);
  }
  std::vector<int> table(V);  // 各頂点が属する木の番号表
  std::iota(table.begin(), table.end(), 0); // 最初は頂点毎に異なる木
  int sum = 0;
  int count = 0;
  
  // 辺を安い順に見る
  std::sort(G.begin(), G.end(), [](const Edge& a, const Edge& b) {
    return a.weight < b.weight;
  });
  for (Edge e : G) {
    // 辺を結んで循環するなら使わない
    if (table[e.endA] == table[e.endB]) continue;

    // 異なる木を結んだら、同じ木にする
    // 変更対象範囲の値を参照渡ししないようにコピーをとる
    std::replace(table.begin(), table.end(), int(table[e.endA]), int(table[e.endB]));

    // 辺を加える
    sum += e.weight;
    if (++count == V - 1) break;  // 全ての頂点を結べば終了(全て結んだあとは循環になるのでこの判定は無くてもいい)
  }

  std::cout << sum << std::endl;
}
accuracy: 1
time_ms: 70
memory_kb: 5076
final_rank: 16

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <vector>
#include <cmath>
#include<sstream>
#include<list>
#include<iomanip>
#include <cstdlib>
#include <cstring>
#include <stack>
#include <bitset>
#include <cassert>
#include <stdlib.h>
#include <stdio.h>
#include <random>
#include <chrono>
using namespace std;
const long long LINF = 3e18 + 7;
const int MAX_N = 5000010;
const int MAX_W = 100002;
const int MAX_ARRAYK = 100000;
double PI = 3.14159265358979323846;
const int INF = 2147483647;
//using ll = long long;

// kruskal
struct edge { long long u, v; long long cost; };
long long V, E;
edge es[MAX_W];
long long par[MAX_N];
long long rank1[MAX_N];
long long siz[MAX_N];

void init(long long n) {
	for (long long i = 0; i < n; i++) {
		par[i] = i;
		rank1[i] = 0;
		siz[i] = 1;
	}
}

long long find(long long x) {
	if (par[x] == x) {
		return x;
	}
	else {
		return par[x] = find(par[x]);
	}
}

void unite(long long x, long long y) {
	x = find(x);
	y = find(y);
	if (x == y) return;

	if (rank1[x] < rank1[y]) {
		par[x] = y;
		siz[y] += siz[x];
	}
	else {
		par[y] = x;
		siz[x] += siz[y];
		if (rank1[x] == rank1[y]) rank1[x]++;
	}
}

bool same(long long x, long long y) {
	return find(x) == find(y);
}

long long usize(long long x) {
	return siz[find(x)];
}

bool comp(const edge& e1, const edge& e2) {
	return e1.cost < e2.cost;
}

long long kruskal() {
	sort(es, es + E, comp);
	init(V);
	long long res = 0;
	for (long long i = 0; i < E; i++) {
		edge e = es[i];
		if (!same(e.u, e.v)) {
			unite(e.u, e.v);
			res += e.cost;
		}
	}
	return res;
}




int main() {

	cin >> V >> E;
	for (long long e = 0; e < E; e++) {
		long long u, v, cost;
		cin >> u >> v >> cost;
		es[e].u = u;
		es[e].v = v;
		es[e].cost = cost;
	}

	cout << kruskal() << endl;

	return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 10312
final_rank: 14

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
#define OVERLOAD_REP(v1, v2, v3, v4, NAME, ...) NAME
#define REP1(i, n) for (int i = 0; (i) < (n); ++(i))
#define REP2(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define REP3(i, l, r, d) for (int i = (l); (i) < (r); (i)+=(d))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_PRE(v1, v2, v3, v4, NAME, ...) NAME
#define PRE1(i, n) for (int i = (n)-1; (i) >= 0; --(i)) // [0,n)
#define PRE2(i, l, r) for (int i = (r)-1; (i) >= (l); --(i)) //[l,r)
#define PRE3(i, l, r, d) for (int i = (r)-1; (i) >= (l); (i)-=(d))
#define pre(...) OVERLOAD_PRE(__VA_ARGS__, PRE3, PRE2, PRE1)(__VA_ARGS__)
#define bg begin()
#define en end()
#define rbg rbegin()
#define ren rend()
#define all(x) x.bg,x.en
#define rall(x) x.rbg,x.ren
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
#define sz(x) ((int)(x).size())
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using sti = stack<int>;
using sei = set<int>;
using qi = queue<int>;
using qii = queue<pii>;
using dqi = deque<int>;
template<class t, class s> using umap = unordered_map<t,s>;
template<class t> using uset = unordered_set<t>;
template<class t> using mset = multiset<t>;
template<class t> using pq=priority_queue<t>;
template<class t> using pqg=priority_queue<t,vector<t>, greater<t>>;
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
template<class t> using vvvc=vc<vc<vc<t>>>;
using vi=vc<int>;
using vvi=vc<vc<int>>;
using vll=vc<ll>;
using vvll=vc<vc<ll>>;
using vd=vc<double>;
using vvd=vc<vc<double>>;
using vb=vc<bool>;
using vvb=vc<vc<bool>>;
using vch=vc<char>;
using vs=vc<string>;
const int inf = 1001001001;
const ll infl = 1LL << 60;
const ll mod = 998244353;
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b; return true;} return false;}
template<class t,class u> bool chmin(t&a,u b){if(a>b){a=b; return true;} return false;}
void yes(){ cout << "Yes" << '\n'; }
void no(){ cout << "No" << '\n'; }

struct Edge{
    int from;
    int to;
    ll cost;
    Edge(int from, int to, ll cost=1): from(from), to(to), cost(cost){}
};
using Graph = vvc<Edge>;

/*  Prim :プリム法でMSTの重みの総和を求める
    Prim(g,r=0): 無向グラフgからrを根とするMSTをつくる
    計算量: O(|E|log|V|)
*/
ll Prim(const Graph &g, int r=0){
	ll sum=0;  // 最小全域木の重みの総和
    vb flag(sz(g));
    using P=pair<ll,int>;
    pqg<P> q;
    q.emplace(0,0);
    while(sz(q)){
        auto [c,u]=q.top(); q.pop();
        if(flag[u]) continue;
        flag[u]=true;
        sum+=c;
        for(auto [from,to,cost]: g[u]){
            if(flag[to]) continue;
            q.emplace(cost,to);
        }
    }
    return sum;
};

int main(){	
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m; cin >> n >> m;
    Graph g(n);
    rep(i,m){
        int s,t; ll c; cin >> s >> t >> c;
        g[s].eb(s,t,c);
        g[t].eb(t,s,c);
    }
    cout << Prim(g) << "\n";
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 10620
final_rank: 12

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
#define OVERLOAD_REP(v1, v2, v3, v4, NAME, ...) NAME
#define REP1(i, n) for (int i = 0; (i) < (n); ++(i))
#define REP2(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define REP3(i, l, r, d) for (int i = (l); (i) < (r); (i)+=(d))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_PRE(v1, v2, v3, v4, NAME, ...) NAME
#define PRE1(i, n) for (int i = (n)-1; (i) >= 0; --(i)) // [0,n)
#define PRE2(i, l, r) for (int i = (r)-1; (i) >= (l); --(i)) //[l,r)
#define PRE3(i, l, r, d) for (int i = (r)-1; (i) >= (l); (i)-=(d))
#define pre(...) OVERLOAD_PRE(__VA_ARGS__, PRE3, PRE2, PRE1)(__VA_ARGS__)
#define bg begin()
#define en end()
#define rbg rbegin()
#define ren rend()
#define all(x) x.bg,x.en
#define rall(x) x.rbg,x.ren
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
#define sz(x) ((int)(x).size())
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using sti = stack<int>;
using sei = set<int>;
using qi = queue<int>;
using qii = queue<pii>;
using dqi = deque<int>;
template<class t, class s> using umap = unordered_map<t,s>;
template<class t> using uset = unordered_set<t>;
template<class t> using mset = multiset<t>;
template<class t> using pq=priority_queue<t>;
template<class t> using pqg=priority_queue<t,vector<t>, greater<t>>;
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
template<class t> using vvvc=vc<vc<vc<t>>>;
using vi=vc<int>;
using vvi=vc<vc<int>>;
using vll=vc<ll>;
using vvll=vc<vc<ll>>;
using vd=vc<double>;
using vvd=vc<vc<double>>;
using vb=vc<bool>;
using vvb=vc<vc<bool>>;
using vch=vc<char>;
using vs=vc<string>;
const int inf = 1001001001;
const ll infl = 1LL << 60;
const ll mod = 998244353;
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b; return true;} return false;}
template<class t,class u> bool chmin(t&a,u b){if(a>b){a=b; return true;} return false;}
void yes(){ cout << "Yes" << '\n'; }
void no(){ cout << "No" << '\n'; }

/* UnionFind
    root(x): xの根。O(α(n))
    size(x): x を含む集合の要素数。
    same(x, y): x と y が同じ集合にいるか。O(α(n))
    merge(x, y): x と y を同じ集合にする。 O(α(n))
*/
struct UF{
    int _n;
    vi par;
    UF(): _n(0){}
    UF(int n): _n(n),par(n,-1){}
    int root(int x){
        if(par[x] < 0) return x;
        return par[x] = root(par[x]); //経路圧縮
    }
    int size(int x){
        return -par[root(x)];
    }
    bool same(int x, int y){
        return root(x) == root(y);
    }
    bool merge(int x, int y){
        int rx = root(x), ry = root(y);
        if(rx == ry) return false;
        if(-par[rx]<-par[ry]) swap(rx,ry);
        par[rx] += par[ry];
        par[ry] = rx;
        return true;
    }
};

struct Edge{
    int from;
    int to;
    ll cost;
    Edge(int from, int to, ll cost=1): from(from), to(to), cost(cost){}
};
using Graph = vvc<Edge>;

/* Kruskal :クラスカル法で minimum spanning tree を求める構造体
    Kruskal(g): 無向グラフgからMSTをつくる
    sum: MSTの重みの総和
    計算量: O(|E|log|V|)
*/
ll kruskal(const Graph &g){
	vc<Edge> edges;
	int n=sz(g);
	ll sum=0;  // 最小全域木の重みの総和
	rep(i,n) for(auto &e: g[i]) edges.pb(e);
	sort(all(edges), [&](Edge a, Edge b){ return a.cost < b.cost; });
	UF uf(n);
	for (auto &e : edges) {
		if (!uf.same(e.from, e.to)) {
			uf.merge(e.from, e.to);
			sum += e.cost;
		}
	}
    return sum;
};

int main(){	
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m; cin >> n >> m;
    Graph g(n);
    rep(i,m){
        int s,t; ll c; cin >> s >> t >> c;
        g[s].eb(s,t,c);
        g[t].eb(t,s,c);
    }
    cout << kruskal(g) << "\n";
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 14252
final_rank: 17

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
#define OVERLOAD_REP(v1, v2, v3, v4, NAME, ...) NAME
#define REP1(i, n) for (int i = 0; (i) < (n); ++(i))
#define REP2(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define REP3(i, l, r, d) for (int i = (l); (i) < (r); (i)+=(d))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_PRE(v1, v2, v3, v4, NAME, ...) NAME
#define PRE1(i, n) for (int i = (n)-1; (i) >= 0; --(i)) // [0,n)
#define PRE2(i, l, r) for (int i = (r)-1; (i) >= (l); --(i)) //[l,r)
#define PRE3(i, l, r, d) for (int i = (r)-1; (i) >= (l); (i)-=(d))
#define pre(...) OVERLOAD_PRE(__VA_ARGS__, PRE3, PRE2, PRE1)(__VA_ARGS__)
#define bg begin()
#define en end()
#define rbg rbegin()
#define ren rend()
#define all(x) x.bg,x.en
#define rall(x) x.rbg,x.ren
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
#define sz(x) ((int)(x).size())
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using sti = stack<int>;
using sei = set<int>;
using qi = queue<int>;
using qii = queue<pii>;
using dqi = deque<int>;
template<class t, class s> using umap = unordered_map<t,s>;
template<class t> using uset = unordered_set<t>;
template<class t> using mset = multiset<t>;
template<class t> using pq=priority_queue<t>;
template<class t> using pqg=priority_queue<t,vector<t>, greater<t>>;
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
template<class t> using vvvc=vc<vc<vc<t>>>;
using vi=vc<int>;
using vvi=vc<vc<int>>;
using vll=vc<ll>;
using vvll=vc<vc<ll>>;
using vd=vc<double>;
using vvd=vc<vc<double>>;
using vb=vc<bool>;
using vvb=vc<vc<bool>>;
using vch=vc<char>;
using vs=vc<string>;
const int inf = 1001001001;
const ll infl = 1LL << 60;
const ll mod = 998244353;
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b; return true;} return false;}
template<class t,class u> bool chmin(t&a,u b){if(a>b){a=b; return true;} return false;}
void yes(){ cout << "Yes" << '\n'; }
void no(){ cout << "No" << '\n'; }

/* UnionFind
    root(x): xの根。O(α(n))
    size(x): x を含む集合の要素数。
    same(x, y): x と y が同じ集合にいるか。O(α(n))
    merge(x, y): x と y を同じ集合にする。 O(α(n))
*/
struct UF{
    int _n;
    vi par;
    UF(): _n(0){}
    UF(int n): _n(n),par(n,-1){}
    int root(int x){
        if(par[x] < 0) return x;
        return par[x] = root(par[x]); //経路圧縮
    }
    int size(int x){
        return -par[root(x)];
    }
    bool same(int x, int y){
        return root(x) == root(y);
    }
    bool merge(int x, int y){
        int rx = root(x), ry = root(y);
        if(rx == ry) return false;
        if(-par[rx]<-par[ry]) swap(rx,ry);
        par[rx] += par[ry];
        par[ry] = rx;
        return true;
    }
};

struct Edge{
    int from;
    int to;
    ll cost;
    Edge(int from, int to, ll cost=1): from(from), to(to), cost(cost){}
};
using Graph = vvc<Edge>;

/* Kruskal :クラスカル法で minimum spanning tree を求める構造体
    Kruskal(g): 無向グラフgからMSTをつくる
    sum: MSTの重みの総和
    計算量: O(|E|log|V|)
*/
struct Kruskal {
	vc<Edge> edges;
	ll sum=0;  // 最小全域木の重みの総和
	int n;
	Kruskal(const Graph &g) : n(sz(g)) {
		rep(i,n) for(auto &e: g[i]) edges.pb(e);
		build();
	}
	void build() {
		sort(all(edges),[&](Edge a, Edge b){ return a.cost < b.cost; });
		UF uf(n);
		for (auto &e : edges) {
			if (!uf.same(e.from, e.to)) {
				uf.merge(e.from, e.to);
				sum += e.cost;
			}
		}
	}
};

int main(){	
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m; cin >> n >> m;
    Graph g(n);
    rep(i,m){
        int s,t; ll c; cin >> s >> t >> c;
        g[s].eb(s,t,c);
        g[t].eb(t,s,c);
    }
    Kruskal k(g);
    cout << k.sum << "\n";
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 14456
final_rank: 18

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
#define OVERLOAD_REP(v1, v2, v3, v4, NAME, ...) NAME
#define REP1(i, n) for (int i = 0; (i) < (n); ++(i))
#define REP2(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define REP3(i, l, r, d) for (int i = (l); (i) < (r); (i)+=(d))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_PRE(v1, v2, v3, v4, NAME, ...) NAME
#define PRE1(i, n) for (int i = (n)-1; (i) >= 0; --(i)) // [0,n)
#define PRE2(i, l, r) for (int i = (r)-1; (i) >= (l); --(i)) //[l,r)
#define PRE3(i, l, r, d) for (int i = (r)-1; (i) >= (l); (i)-=(d))
#define pre(...) OVERLOAD_PRE(__VA_ARGS__, PRE3, PRE2, PRE1)(__VA_ARGS__)
#define bg begin()
#define en end()
#define rbg rbegin()
#define ren rend()
#define all(x) x.bg,x.en
#define rall(x) x.rbg,x.ren
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
#define sz(x) ((int)(x).size())
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using sti = stack<int>;
using sei = set<int>;
using qi = queue<int>;
using qii = queue<pii>;
using dqi = deque<int>;
template<class t, class s> using umap = unordered_map<t,s>;
template<class t> using uset = unordered_set<t>;
template<class t> using mset = multiset<t>;
template<class t> using pq=priority_queue<t>;
template<class t> using pqg=priority_queue<t,vector<t>, greater<t>>;
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
template<class t> using vvvc=vc<vc<vc<t>>>;
using vi=vc<int>;
using vvi=vc<vc<int>>;
using vll=vc<ll>;
using vvll=vc<vc<ll>>;
using vd=vc<double>;
using vvd=vc<vc<double>>;
using vb=vc<bool>;
using vvb=vc<vc<bool>>;
using vch=vc<char>;
using vs=vc<string>;
const int inf = 1001001001;
const ll infl = 1LL << 60;
const ll mod = 998244353;
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b; return true;} return false;}
template<class t,class u> bool chmin(t&a,u b){if(a>b){a=b; return true;} return false;}
void yes(){ cout << "Yes" << '\n'; }
void no(){ cout << "No" << '\n'; }

struct Edge{
    int from;
    int to;
    ll cost;
    Edge(int from, int to, ll cost=1): from(from), to(to), cost(cost){}
};
using Graph = vvc<Edge>;

/*  Prim :プリム法で minimum spanning tree を求める構造体
    Prim(g,r): 無向グラフgからrを根とするMSTをつくる
    sum: 最小全域木の重みの総和
    計算量: O(|E|log|V|)
*/
struct Prim {
	ll sum=0;  // 最小全域木の重みの総和
	Prim(const Graph &g, int r=0){
        vb flag(sz(g));
        using P=pair<ll,int>;
        pqg<P> q;
        q.emplace(0,0);
        while(sz(q)){
            auto [c,u]=q.top(); q.pop();
            if(flag[u]) continue;
            flag[u]=true;
            sum+=c;
            for(auto [from,to,cost]: g[u]){
                if(flag[to]) continue;
                q.emplace(cost,to);
            }
        }
    }
};


int main(){	
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m; cin >> n >> m;
    Graph g(n);
    rep(i,m){
        int s,t; ll c; cin >> s >> t >> c;
        g[s].eb(s,t,c);
        g[t].eb(t,s,c);
    }
    Prim k(g);
    cout << k.sum << "\n";
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 10628
final_rank: 13

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
#define OVERLOAD_REP(v1, v2, v3, v4, NAME, ...) NAME
#define REP1(i, n) for (int i = 0; (i) < (n); ++(i))
#define REP2(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define REP3(i, l, r, d) for (int i = (l); (i) < (r); (i)+=(d))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_PRE(v1, v2, v3, v4, NAME, ...) NAME
#define PRE1(i, n) for (int i = (n)-1; (i) >= 0; --(i)) // [0,n)
#define PRE2(i, l, r) for (int i = (r)-1; (i) >= (l); --(i)) //[l,r)
#define PRE3(i, l, r, d) for (int i = (r)-1; (i) >= (l); (i)-=(d))
#define pre(...) OVERLOAD_PRE(__VA_ARGS__, PRE3, PRE2, PRE1)(__VA_ARGS__)
#define bg begin()
#define en end()
#define rbg rbegin()
#define ren rend()
#define all(x) x.bg,x.en
#define rall(x) x.rbg,x.ren
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
#define sz(x) ((int)(x).size())
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using sti = stack<int>;
using sei = set<int>;
using qi = queue<int>;
using qii = queue<pii>;
using dqi = deque<int>;
template<class t, class s> using umap = unordered_map<t,s>;
template<class t> using uset = unordered_set<t>;
template<class t> using mset = multiset<t>;
template<class t> using pq=priority_queue<t>;
template<class t> using pqg=priority_queue<t,vector<t>, greater<t>>;
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
template<class t> using vvvc=vc<vc<vc<t>>>;
using vi=vc<int>;
using vvi=vc<vc<int>>;
using vll=vc<ll>;
using vvll=vc<vc<ll>>;
using vd=vc<double>;
using vvd=vc<vc<double>>;
using vb=vc<bool>;
using vvb=vc<vc<bool>>;
using vch=vc<char>;
using vs=vc<string>;
const int inf = 1001001001;
const ll infl = 1LL << 60;
const ll mod = 998244353;
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b; return true;} return false;}
template<class t,class u> bool chmin(t&a,u b){if(a>b){a=b; return true;} return false;}
void yes(){ cout << "Yes" << '\n'; }
void no(){ cout << "No" << '\n'; }

/* UnionFind
    root(x): xの根。O(α(n))
    size(x): x を含む集合の要素数。
    same(x, y): x と y が同じ集合にいるか。O(α(n))
    merge(x, y): x と y を同じ集合にする。 O(α(n))
*/
struct UF{
    int _n;
    vi par;
    UF(): _n(0){}
    UF(int n): _n(n),par(n,-1){}
    int root(int x){
        if(par[x] < 0) return x;
        return par[x] = root(par[x]); //経路圧縮
    }
    int size(int x){
        return -par[root(x)];
    }
    bool same(int x, int y){
        return root(x) == root(y);
    }
    bool merge(int x, int y){
        int rx = root(x), ry = root(y);
        if(rx == ry) return false;
        if(-par[rx]<-par[ry]) swap(rx,ry);
        par[rx] += par[ry];
        par[ry] = rx;
        return true;
    }
};

struct Edge{
    int from;
    int to;
    ll cost;
    Edge(int from, int to, ll cost=1): from(from), to(to), cost(cost){}
};
using Graph = vvc<Edge>;

/* Kruskal :クラスカル法で minimum spanning tree を求める構造体
    Kruskal(g): 無向グラフgからMSTをつくる
    sum: MSTの重みの総和
    計算量: O(|E|log|V|)
*/
struct Kruskal {
	vc<Edge> edges;
	ll sum=0;  // 最小全域木の重みの総和
	int n;
	Kruskal(const Graph &g) : n(sz(g)) {
		rep(i,n) for(auto &e: g[i]) edges.pb(e);
		build();
	}
	void build() {
		sort(all(edges),[&](Edge a, Edge b){ return a.cost < b.cost; });
		UF uf(n);
		for (auto &e : edges) {
			if (!uf.same(e.from, e.to)) {
				uf.merge(e.from, e.to);
				sum += e.cost;
			}
		}
	}
};

int main(){	
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m; cin >> n >> m;
    Graph g(n);
    rep(i,m){
        int s,t; ll c; cin >> s >> t >> c;
        g[s].eb(s,t,c);
    }
    Kruskal k(g);
    cout << k.sum << "\n";
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 8028
final_rank: 4

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
#define OVERLOAD_REP(v1, v2, v3, v4, NAME, ...) NAME
#define REP1(i, n) for (int i = 0; (i) < (n); ++(i))
#define REP2(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define REP3(i, l, r, d) for (int i = (l); (i) < (r); (i)+=(d))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_PRE(v1, v2, v3, v4, NAME, ...) NAME
#define PRE1(i, n) for (int i = (n)-1; (i) >= 0; --(i)) // [0,n)
#define PRE2(i, l, r) for (int i = (r)-1; (i) >= (l); --(i)) //[l,r)
#define PRE3(i, l, r, d) for (int i = (r)-1; (i) >= (l); (i)-=(d))
#define pre(...) OVERLOAD_PRE(__VA_ARGS__, PRE3, PRE2, PRE1)(__VA_ARGS__)
#define bg begin()
#define en end()
#define rbg rbegin()
#define ren rend()
#define all(x) x.bg,x.en
#define rall(x) x.rbg,x.ren
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
#define sz(x) ((int)(x).size())
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using sti = stack<int>;
using sei = set<int>;
using qi = queue<int>;
using qii = queue<pii>;
using dqi = deque<int>;
template<class t, class s> using umap = unordered_map<t,s>;
template<class t> using uset = unordered_set<t>;
template<class t> using mset = multiset<t>;
template<class t> using pq=priority_queue<t>;
template<class t> using pqg=priority_queue<t,vector<t>, greater<t>>;
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
template<class t> using vvvc=vc<vc<vc<t>>>;
using vi=vc<int>;
using vvi=vc<vc<int>>;
using vll=vc<ll>;
using vvll=vc<vc<ll>>;
using vd=vc<double>;
using vvd=vc<vc<double>>;
using vb=vc<bool>;
using vvb=vc<vc<bool>>;
using vch=vc<char>;
using vs=vc<string>;
const int inf = 1001001001;
const ll infl = 1LL << 60;
const ll mod = 998244353;
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b; return true;} return false;}
template<class t,class u> bool chmin(t&a,u b){if(a>b){a=b; return true;} return false;}
void yes(){ cout << "Yes" << '\n'; }
void no(){ cout << "No" << '\n'; }

/* UnionFind
    root(x): xの根。O(α(n))
    size(x): x を含む集合の要素数。
    same(x, y): x と y が同じ集合にいるか。O(α(n))
    merge(x, y): x と y を同じ集合にする。 O(α(n))
*/
struct UF{
    int _n;
    vi par;
    UF(): _n(0){}
    UF(int n): _n(n),par(n,-1){}
    int root(int x){
        if(par[x] < 0) return x;
        return par[x] = root(par[x]); //経路圧縮
    }
    int size(int x){
        return -par[root(x)];
    }
    bool same(int x, int y){
        return root(x) == root(y);
    }
    bool merge(int x, int y){
        int rx = root(x), ry = root(y);
        if(rx == ry) return false;
        if(-par[rx]<-par[ry]) swap(rx,ry);
        par[rx] += par[ry];
        par[ry] = rx;
        return true;
    }
};

struct Edge{
    int from;
    int to;
    ll cost;
    Edge(int from, int to, ll cost=1): from(from), to(to), cost(cost){}
};
using Graph = vvc<Edge>;

/* Kruskal :クラスカル法で minimum spanning tree を求める構造体
    入力: Graph g
    最小全域木の重みの総和: sum
    計算量: O(|E|log|V|)
*/
struct Kruskal {
	UF uf;
	vc<Edge> edges;
	ll sum;  // 最小全域木の重みの総和
	int n;
	Kruskal(const Graph &g) : n(sz(g)) {
		rep(i,n) for(auto &e: g[i]) edges.pb(e);
		init();
	}
	void init() {
		sort(all(edges),[&](Edge a, Edge b)->bool{
			return a.cost < b.cost;
		});
		uf = UF(n);
		sum = 0;
		for (auto &e : edges) {
			if (!uf.same(e.from, e.to)) {
				uf.merge(e.from, e.to);
				sum += e.cost;
			}
		}
	}
};

int main(){	
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m; cin >> n >> m;
    Graph g(n);
    rep(i,m){
        int s,t; ll c; cin >> s >> t >> c;
        g[s].eb(s,t,c);
    }
    Kruskal k(g);
    cout << k.sum << "\n";
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 8040
final_rank: 6

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
#define OVERLOAD_REP(v1, v2, v3, v4, NAME, ...) NAME
#define REP1(i, n) for (int i = 0; (i) < (n); ++(i))
#define REP2(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define REP3(i, l, r, d) for (int i = (l); (i) < (r); (i)+=(d))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_PRE(v1, v2, v3, v4, NAME, ...) NAME
#define PRE1(i, n) for (int i = (n)-1; (i) >= 0; --(i)) // [0,n)
#define PRE2(i, l, r) for (int i = (r)-1; (i) >= (l); --(i)) //[l,r)
#define PRE3(i, l, r, d) for (int i = (r)-1; (i) >= (l); (i)-=(d))
#define pre(...) OVERLOAD_PRE(__VA_ARGS__, PRE3, PRE2, PRE1)(__VA_ARGS__)
#define bg begin()
#define en end()
#define rbg rbegin()
#define ren rend()
#define all(x) x.bg,x.en
#define rall(x) x.rbg,x.ren
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
#define sz(x) ((int)(x).size())
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using sti = stack<int>;
using sei = set<int>;
using qi = queue<int>;
using qii = queue<pii>;
using dqi = deque<int>;
template<class t, class s> using umap = unordered_map<t,s>;
template<class t> using uset = unordered_set<t>;
template<class t> using mset = multiset<t>;
template<class t> using pq=priority_queue<t>;
template<class t> using pqg=priority_queue<t,vector<t>, greater<t>>;
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
template<class t> using vvvc=vc<vc<vc<t>>>;
using vi=vc<int>;
using vvi=vc<vc<int>>;
using vll=vc<ll>;
using vvll=vc<vc<ll>>;
using vd=vc<double>;
using vvd=vc<vc<double>>;
using vb=vc<bool>;
using vvb=vc<vc<bool>>;
using vch=vc<char>;
using vs=vc<string>;
const int inf = 1001001001;
const ll infl = 1LL << 60;
const ll mod = 998244353;
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b; return true;} return false;}
template<class t,class u> bool chmin(t&a,u b){if(a>b){a=b; return true;} return false;}
void yes(){ cout << "Yes" << '\n'; }
void no(){ cout << "No" << '\n'; }

/* UnionFind
    root(x): xの根。O(α(n))
    size(x): x を含む集合の要素数。
    same(x, y): x と y が同じ集合にいるか。O(α(n))
    merge(x, y): x と y を同じ集合にする。 O(α(n))
*/
struct UF{
    int _n;
    vi par;
    UF(): _n(0){}
    UF(int n): _n(n),par(n,-1){}
    int root(int x){
        if(par[x] < 0) return x;
        return par[x] = root(par[x]); //経路圧縮
    }
    int size(int x){
        return -par[root(x)];
    }
    bool same(int x, int y){
        return root(x) == root(y);
    }
    bool merge(int x, int y){
        int rx = root(x), ry = root(y);
        if(rx == ry) return false;
        if(-par[rx]<-par[ry]) swap(rx,ry);
        par[rx] += par[ry];
        par[ry] = rx;
        return true;
    }
};

struct Edge{
    int from;
    int to;
    ll cost;
    Edge(int from, int to, ll cost=1): from(from), to(to), cost(cost){}
};
using Graph = vvc<Edge>;

/* Kruskal :クラスカル法で minimum spanning tree を求める構造体
    入力: Graph g
    最小全域木の重みの総和: sum
    計算量: O(|E|log|V|)
*/
struct Kruskal {
	UF uf;
	vc<Edge> edges;
	ll sum;  // 最小全域木の重みの総和
	int n;
	Kruskal(const Graph &g) : n(g.size()) {
		rep(i,n) for(auto &e: g[i]) edges.pb(e);
		init();
	}
	void init() {
		sort(all(edges),[&](Edge a, Edge b)->bool{
			return a.cost < b.cost;
		});
		uf = UF(n);
		sum = 0;
		for (auto &e : edges) {
			if (!uf.same(e.from, e.to)) {
				uf.merge(e.from, e.to);
				sum += e.cost;
			}
		}
	}
};

int main(){	
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m; cin >> n >> m;
    Graph g(n);
    rep(i,m){
        int s,t; ll c; cin >> s >> t >> c;
        g[s].eb(s,t,c);
    }
    Kruskal k(g);
    cout << k.sum << "\n";
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 8032
final_rank: 5

code_snippet: //原理是利用互斥集合（union-find)将边升序排列保证不出现环的情况下放入（n-1）条边
//用上节课学的讲一个类的class（两个端点加边的权值）放进vecotr啊！！！
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAX=10000;
class disjointset{//创个互斥集合来判断放哪些边
    public:
    vector<int> p,rank;
    disjointset(){}
    disjointset(int size){
        p.resize(size,0);
        rank.resize(size,0);
        for(int i=0;i<size;i++){
            makeset(i);
        }
    }
    void makeset(int i){
        p[i]=i;
        rank[i]=0;
    }
    bool same(int a,int b){
        return findset(a)==findset(b);
    }
    int findset(int a){
        if(a!=p[a]){
            p[a]=findset(p[a]);
        }
        return p[a];
    }
    void unite(int a,int b){
        link(findset(a),findset(b));
    }
    void link(int a,int b){
        if(rank[a]>rank[b]){
            p[b]=a;
        }else {
            p[a]=b;
            if(rank[a]==rank[b]){
                rank[b]++;
            }
        }
    }
};
class Edge{
    public:
    int source;
    int target;
    int weight;
    Edge(int a,int b,int c):source(a),target(b),weight(c){}
};
    bool edges(const Edge &a,const Edge &b){//注意自定义比较规则，引用前是类型后面你随便加个标识符,也可以在edge改变控制符
        return a.weight<b.weight;
    }
vector<Edge> A;
int main(){
    int V,E;
    scanf("%d %d",&V,&E);
    disjointset ds=disjointset(V+1);
    long long sum=0;
    for(int i=0;i<E;i++){
        int s,t,w;
        scanf("%d %d %d",&s,&t,&w);
        A.push_back(Edge(s,t,w));//在类定义完初始化方式，就可以pushback直接放进去
    }
    sort(A.begin(),A.end(),edges);
    int q=0;
    int i=0;
    while(q!=(V-1)){//从小到大放进n-1条边
        if(!ds.same(A[i].source,A[i].target)){
            ds.unite(A[i].source,A[i].target);
            q++;
            sum+=A[i].weight;
        }//可以不用外部指示器而只用并查集，因为放入n-1条边后之后same的判断肯定始终都是false
        i++;
    }
    printf("%lld\n",sum);
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 4312
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;







class UnionFind {
    public:
    int par[100009];
    int siz[100009];

    void init(int n) {
        for(int i = 0; i < n; i++) par[i] = -1;
        for(int i = 0; i < n; i++) siz[i] = 1;
    }

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

    void unite(int v, int u) {
        int rv = root(v), ru = root(u);
        if(rv == ru) return ;

        if(siz[rv] > siz[ru]) {
            par[ru] = rv;
            siz[rv] += siz[ru];
        } else {
            par[rv] = ru;
            siz[ru] += siz[rv];
        }
    }

    bool same(int v, int u) {
        return root(v) == root(u);
    }
};








int main() {
    int N, M; cin >> N >> M;
    vector<vector<pair<int, int>>> g(N);

    vector<int> A(M), B(M), C(M);

    for(int i = 0; i < M; i++) {
        cin >> A[i] >> B[i] >> C[i];
    }

    vector<pair<int, int>> len(M);
    for(int i = 0; i < M; i++) len[i] = {C[i], i};

    sort(len.begin(), len.end());


    UnionFind UF;
    UF.init(N);

    int ans = 0;
    for(int i = 0; i < M; i++) {
        int pos = len[i].second;
        if(UF.same(A[pos], B[pos])) continue;
        UF.unite(A[pos], B[pos]);
        ans += C[pos];
    }

    cout << ans << endl;
}
accuracy: 1
time_ms: 40
memory_kb: 5452
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

class UnionFind {
    public:
    int par[100009];
    int siz[100009];

    // N 頂点の Union-Findを作成
    void init(int N) {
        for(int i = 0; i < N; i++) par[i] = -1;
        for(int i = 0; i < N; i++) siz[i] = 1;
    }

    // 頂点 x の根を返す関数
    int root(int x) {
        while(true) {
            if(par[x] == -1) break;
            x = par[x];
        }

        return x;
    }

    // 要素 u と v を結合する関数
    void unite(int u, int v) {
        int rootU = root(u);
        int rootV = root(v);
        if(rootU == rootV) return;

        if(siz[rootU] < siz[rootV]) {
            par[rootU] = rootV;
            siz[rootV] += siz[rootU];
        } else {
            par[rootV] = rootU;
            siz[rootU] += siz[rootV];
        }
    }

    // 要素 u と v が同じグループに属しているかどうか返す関数
    bool same(int u, int v) {
        return root(u) == root(v);
    }
};








int main() {
    int N, M; cin >> N >> M;
    UnionFind UF;
    vector<int> s(M), t(M), w(M);
    for(int i = 0; i < M; i++) cin >> s[i] >> t[i] >> w[i];

    vector<pair<int, int>> EdgeList;
    for(int i = 0; i < M; i++) EdgeList.push_back({w[i], i});
    sort(EdgeList.begin(), EdgeList.end());

    int ans = 0;
    UF.init(N);
    for(int i = 0; i < EdgeList.size(); i++) {
        int index = EdgeList[i].second;
        if(UF.same(s[index], t[index])) continue;
        UF.unite(s[index], t[index]);
        ans += w[index];
    }

    cout << ans << endl;
}
accuracy: 1
time_ms: 40
memory_kb: 5276
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for (int i = a; i < n; ++i)
#define rrep(i, a, n) for (int i = n - 1; i >= a; --i)
using ll = long long;
using ld = long double;
using pl = pair<ll, ll>;
using vl = vector<ll>;
using vvl = vector<vl>;
using vp = vector<pl>;
using vvp = vector<vp>;
using vb = vector<bool>;
using vvb = vector<vb>;
using vs = vector<string>;
using vc = vector<char>;
using vvc = vector<vc>;
const int mod = 1000000007;
const ll hashh = 2147483647;

#ifndef ATCODER_DSU_HPP
#define ATCODER_DSU_HPP 1

#include <algorithm>
#include <cassert>
#include <vector>

namespace atcoder
{

    // Implement (union by size) + (path compression)
    // Reference:
    // Zvi Galil and Giuseppe F. Italiano,
    // Data structures and algorithms for disjoint set union problems
    struct dsu
    {
    public:
        dsu() : _n(0) {}
        explicit dsu(int n) : _n(n), parent_or_size(n, -1) {}

        int merge(int a, int b)
        {
            assert(0 <= a && a < _n);
            assert(0 <= b && b < _n);
            int x = leader(a), y = leader(b);
            if (x == y)
                return x;
            if (-parent_or_size[x] < -parent_or_size[y])
                std::swap(x, y);
            parent_or_size[x] += parent_or_size[y];
            parent_or_size[y] = x;
            return x;
        }

        bool same(int a, int b)
        {
            assert(0 <= a && a < _n);
            assert(0 <= b && b < _n);
            return leader(a) == leader(b);
        }

        int leader(int a)
        {
            assert(0 <= a && a < _n);
            return _leader(a);
        }

        int size(int a)
        {
            assert(0 <= a && a < _n);
            return -parent_or_size[leader(a)];
        }

        std::vector<std::vector<int>> groups()
        {
            std::vector<int> leader_buf(_n), group_size(_n);
            for (int i = 0; i < _n; i++)
            {
                leader_buf[i] = leader(i);
                group_size[leader_buf[i]]++;
            }
            std::vector<std::vector<int>> result(_n);
            for (int i = 0; i < _n; i++)
            {
                result[i].reserve(group_size[i]);
            }
            for (int i = 0; i < _n; i++)
            {
                result[leader_buf[i]].push_back(i);
            }
            result.erase(
                std::remove_if(result.begin(), result.end(),
                               [&](const std::vector<int> &v)
                               { return v.empty(); }),
                result.end());
            return result;
        }

    private:
        int _n;
        // root node: -1 * component size
        // otherwise: parent
        std::vector<int> parent_or_size;

        int _leader(int a)
        {
            if (parent_or_size[a] < 0)
                return a;
            return parent_or_size[a] = _leader(parent_or_size[a]);
        }
    };

} // namespace atcoder

#endif // ATCODER_DSU_HPP

using namespace atcoder;

// main
int main()
{
    ll v, e, ans = 0;
    cin >> v >> e;
    dsu d(v);
    vector<tuple<ll, ll, ll>> s(e);
    rep(i, 0, e)
    {
        cin >> get<1>(s[i]) >> get<2>(s[i]) >> get<0>(s[i]);
    }
    sort(s.begin(), s.end());
    rep(i, 0, e)
    {
        if (!d.same(get<1>(s[i]), get<2>(s[i])))
        {
            d.merge(get<1>(s[i]), get<2>(s[i]));
            ans += get<0>(s[i]);
        }
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 40
memory_kb: 5420
final_rank: 8

code_snippet: #include <iostream>
#include <vector>
#include <queue>

const int MAXN = 10000;

struct Edge {
    int s;
    int t;
    int w;

    Edge(int s, int t, int w): s(s), t(t), w(w) {}
    int either() { return s; }
    int other(int v) { if (v == s) return t; return s; }
    int weight() { return w; }
};

struct EdgeCompare {
    bool operator()(const Edge& lhs, const Edge& rhs) const {
        return lhs.w > rhs.w;
    }
};

std::vector<Edge> G[MAXN];
bool visited[MAXN];
std::priority_queue<Edge, std::vector<Edge>, EdgeCompare> pq;
std::queue<Edge> mst;

void visit(int v)
{
    visited[v] = true;
    for (int i = 0; i < G[v].size(); ++i) {
        if (!visited[G[v][i].other(v)]) {
            pq.push(G[v][i]);
        }
    }
}

int main()
{
    int v, e;
    std::cin >> v >> e;
    for (int i = 0; i < e; ++i) {
        int s, t, w;
        std::cin >> s >> t >> w;
        G[s].push_back(Edge(s, t, w));
        G[t].push_back(Edge(t, s, w));
    }

    visit(0);
    while (!pq.empty()) {
        Edge e = pq.top();
        pq.pop();
        int v = e.either();
        int w = e.other(v);
        if (visited[v] && visited[w]) continue;
        mst.push(e);
        if (!visited[v]) visit(v);
        if (!visited[w]) visit(w);
    }

    int weight = 0;
    while (!mst.empty()) {
        Edge e = mst.front();
        mst.pop();
        weight += e.weight();
    }
    std::cout << weight << std::endl;

    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 9024
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
#if __has_include(<atcoder/all>)
#include <atcoder/math>
using namespace atcoder;
#endif

using ll = long long;
using vi = vector<int>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vll = vector<ll>;
using vvll = vector<vector<ll>>;
using vvvll = vector<vector<vector<ll>>>;
using vstr = vector<string>;
using vchr = vector<char>;
using pii = pair<int,int>;
using pll = pair<long long, long long>;
using Graph = vector<vector<int>>;
const int dx[8] = {1, 0, -1, 0, 1, 1, -1, -1};
const int dy[8] = {0, 1, 0, -1, 1, -1, 1, -1};

#define rep(i, a, b) for(int i = (int)a; i < (int)b; i++)
#define REP(i, a, b) for (int i = (int)a; i <= (int)b; i++)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
#define YESNO(flag) cout << (flag ? "Yes" : "No") << "\n"
#define spa " "

const int inf = 1070000000;
const long long INF = 4500000000000000000;
const long long MOD = 998244353;
//const long long MOD = 1000000007;
const double pi = 3.141592653589793238;
const string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string abc = "abcdefghijklmnopqrstuvwxyz";

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

//xのn乗
ll llpow(ll x, ll n) {
    ll ans = 1;
    while(n > 0) {
        if(n & 1) ans *= x;
        x *= x;
        n >>= 1; 
    }
    return ans;
}
ll modpow(ll x, ll n, ll mod) {
    ll ans = 1;
    while(n > 0) {
        if(n & 1) ans = ans * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return ans;
}
//mod pでのaの逆元
ll inverse(ll a, ll p) {
    return modpow(a, p-2, p);
}
//nの階乗
ll fact(ll n) {
    if(n == 0) return 1;
    else return n * fact(n-1);
}
ll modfact(ll n, ll mod) {
    if(n == 0) return 1;
    else return (n * modfact(n-1, mod)) % mod;
}
//nCr=n!/r!(n-r)! mod p
ll comb(ll n, ll r, ll mod) {
    ll a = modfact(n, mod), b = modfact(r, mod), c = modfact(n-r, mod);
    b = inverse(b, mod); c = inverse(c, mod);
    return (((a*b)%mod)*c)%mod;
}

//1+2+...+n = n(n+1)/2
ll triangle(ll n) {
    ll x = n*(n+1);
    return x/2;
}
//素数判定
bool is_prime(long long x) {
    if(x == 1) return false;
    
    for(long long i = 2; i*i <= x; i++) {
        if(x % i == 0) return false;
    }
    return true;
}

//座標圧縮
vector<int> compress(vector<int> A) {
    vector<int> B = A;

    sort(B.begin(), B.end());
    B.erase(unique(B.begin(), B.end()), B.end());

    vector<int> res(A.size());
    for(int i = 0; i < (int)A.size(); i++) {
        res[i] = lower_bound(B.begin(), B.end(), A[i]) - B.begin();
    }
    return res;
}

//正方形グリッドの右回転
void rotate_right(vector<vector<char>> &S) {
    int N = S.size();
    auto T = S;
    rep(i,0,N) rep(j,0,N) {
        T[i][j] = S[N-1-j][i];
    }
    S = T;
}
//左回転
void rotate_left(vector<vector<char>> &S) {
    int N = S.size();
    auto T = S;
    rep(i,0,N) rep(j,0,N) {
        T[i][j] = S[j][N-1-i];
    }
    S = T;
}

//2点(a,b)と(x,y)の距離
double dist(ll a, ll b, ll x, ll y) {
    return sqrt((a-x)*(a-x) + (b-y)*(b-y));
}
int man(int a, int b, int x, int y) {
    return abs(a-x) + abs(b-y);
}

//桁数
int digit(ll N) {
    if(N <= 9) return 1;

    return 1 + digit(N / 10);
}
//A進数文字列NをB進数に変換. A,Bは10以下
string base_change(string N, ll A, ll B) {
    ll X = stoll(N), Y = 0;

    ll i = 1;
    while(X != 0) {
        Y += (X % 10) * i;
        i *= A;
        X /= 10;
    }

    X = Y, Y = 0;
    i = 1;
    while(X != 0) {
        Y += (X % B) * i;
        i *= 10;
        X /= B;
    }

    return to_string(Y);
}
//回文判定
bool palin(string S) {
    rep(i,0,S.size()) {
        if(S[i] != S[S.size()-1-i]) return false;
    }
    return true;
}

//hh:mm:ss to second
int convert_to_time(string S) {
    ll h = 10*(S[0]-'0') + (S[1]-'0');
    ll m = 10*(S[3]-'0') + (S[4]-'0');
    ll s = 10*(S[6]-'0') + (S[7]-'0');
    
    return h*3600+m*60+s;
}

//DFS
void dfs(const Graph &G, int v, vector<bool> &seen) { 
    seen[v] = true;
    
    for (auto next_v : G[v]) { 
        if (!seen[next_v]) {
            dfs(G, next_v, seen);
        }
    }
}
void griddfs(const vector<vector<char>> &G, int x, int y, vector<vector<bool>> &seen) {
    int H = G.size(), W = G[0].size();
    seen[x][y] = true;
    
    for (int i = 0; i < 8; i++) { 
        int nx = x + dx[i], ny = y + dy[i];
        if(nx < 0 or nx >= H or ny < 0 or ny >= W) continue;
        if (!seen[nx][ny] and G[nx][ny] != '#') griddfs(G, nx, ny, seen);
    }
}
//BFS
void bfs(const Graph &G, int v, vector<int> &dist) {
    rep(i,0,dist.size()) dist[i] = inf;
    dist[v] = 0;
    queue<int> q;
    q.push(v);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(auto next_u : G[u]) {
            if(dist[next_u] == inf) {
                dist[next_u] = dist[u] + 1;
                q.push(next_u);
            }
        }
    }
}
void gridbfs(const vector<vector<char>> &G, int x, int y, vector<vector<int>> &dist) {
    int H = G.size(), W = G[0].size();
    rep(i,0,H) rep(j,0,W) dist[i][j] = inf;
    dist[x][y] = 0;
    queue<pair<int, int>> q;
    q.push(make_pair(x, y));
    while(!q.empty()) {
        int x = q.front().first, y = q.front().second;
        q.pop();
        for(int i = 0; i < 4; i++) {
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 0 or nx >= H or ny < 0 or ny >= W) continue;
            if(dist[nx][ny] == inf and G[nx][ny] != '#') {
                dist[nx][ny] = dist[x][y] + 1;
                q.push(make_pair(nx, ny));
            }
        }
    }
}
//ワーシャル・フロイド
vector<vector<ll>> floyd(vector<vector<ll>> G) {
    int N = G.size();
    auto dp = G;
    for (int k = 0; k < N; k++){
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if(dp[i][j] > dp[i][k] + dp[k][j] and dp[i][k] != INF and dp[k][j] != INF) {
                    dp[i][j] = dp[i][k] + dp[k][j];
                }
            }
        }
    }
    return dp;
}

//Union-Find
struct UnionFind {
    vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2
    
    UnionFind(int N) : par(N) { //最初は全てが根であるとして初期化
        for(int i = 0; i < N; i++) par[i] = i;
    }
    
    int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
        if (par[x] == x) return x;
        return par[x] = root(par[x]);
    }
    
    void unite(int x, int y) { // xとyの木を併合
        int rx = root(x); //xの根をrx
        int ry = root(y); //yの根をry
        if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
        par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
    }
    
    bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
        int rx = root(x);
        int ry = root(y);
        return rx == ry;
    }
};

void solve() {
}

int main() {
    int V, E; cin >> V >> E;
    priority_queue<tuple<int,int,int>, vector<tuple<int,int,int>>, greater<tuple<int,int,int>>> q;
    rep(i,0,E) {
        int s, t, w; cin >> s >> t >> w;
        q.push(make_tuple(w,s,t));
    }

    UnionFind tree(V);
    ll ans = 0;
    while(!q.empty()) {
        int w, s, t;
        tie(w, s, t) = q.top();
        if(!tree.same(s,t)) {
            ans += w;
            tree.unite(s,t);
        }
        q.pop();
    }
    cout << ans << "\n";

    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 4820
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for (int i=0; i<n; i++)

class DisjointSet {
    public:
        vector<int> rank, p;
        DisjointSet() = default;
        DisjointSet(int size) {
            rank.resize(size,0);
            p.resize(size,0);
            for (int i=0; i<size; i++) makeSet(i);
        }

        void makeSet(int x) {
            p[x] = x;
            rank[x] = 0;
        }

        bool same(int x, int y) {
            return findSet(x) == findSet(y);
        }

        void unite(int x, int y) {
            link(findSet(x), findSet(y));
        }

        void link(int x, int y) {
            if (rank[x] > rank[y]) {
                p[y] = x;
            } else {
                p[x] = y;
                if (rank[x] == rank[y]) {
                    rank[y]++;
                }
            }
        }

        int findSet(int x) {
            if (x != p[x]) {
                p[x] = findSet(p[x]);
            }
            return p[x];
        }
};


struct Edge {
    int s, t, cost;
    Edge() = default;
    Edge(int s, int t, int cost) : s(s), t(t), cost(cost) {}
    bool operator<(const Edge &other) const {
        return cost < other.cost;
    }
};

int kruskal(int v, vector<Edge> e) {
    sort(e.begin(), e.end());
    DisjointSet ds(v);
    int res = 0;

    for (Edge x : e) {
        if (!ds.same(x.s, x.t)) {
            ds.unite(x.s, x.t);
            res += x.cost;
        }
    }
    return res;
}

int main()
{
    int v, e;
    cin >> v >> e;
    vector<Edge> a(e);
    rep(i,e) cin >> a[i].s >> a[i].t >> a[i].cost;
    
    int ans = kruskal(v,a);

    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 5492
final_rank: 10