Problem:
Problem H : Dungeon (II)
あなたはとあるゲームの開発に携わっている。
そのゲームはランダムに生成されたダンジョンをプレイヤーが探索するというものである。
ゲームの仕様として、プレイヤーに予めダンジョンの危険度を提示し、生成されたダンジョンを探索するのか、それとも新しくダンジョンを生成しなおすかを、選択できるようにしたい。
このゲームで生成されるダンジョンには
n
個の部屋が存在しており、0から
n-1
までの番号が割り振られている。
部屋と部屋は通路で結ばれている。部屋と部屋を結ぶ通路は、合計で
n-1
本存在している。
通路はどちらの方向へも進むことができる。
また、部屋と部屋の間には距離が設定されている。
生成されたダンジョンではいくつかの通路を経由して、ある部屋から他のすべての部屋へ行くことが可能である。
そして、プレイヤーがゲームを行う際に、２つの異なる部屋がスタート地点とゴール地点として選ばれる。
あなたはダンジョンの評価を行うために、危険度の評価方法を決めることにした。
まず、ある部屋から別の部屋までに移動する際の危険度を、部屋間を最短で移動するために使う通路の中で、最もコスト高い通路の値とする。
そして、ダンジョンの危険度を、
i
<
j
となる部屋のペアの間を移動する際の危険度の総和とすることにした。
ランダムに生成されたダンジョンのが入力として与えられる。
まず、
i
<
j
となるすべての部屋のペアについて、移動する際の危険度を計算して欲しい。
そして、その総和を問題の答えとして出力せよ。
Input
入力は以下のフォーマットで与えられる。
n
a
1
b
1
c
1
.
.
.
a
n-1
b
n-1
c
n-1
a
i
b
i
c
i
は 部屋
a
i
と
b
i
を結ぶ通路の距離が
c
i
であることを表す。
入力は以下の制約を満たす
2 ≤
n
≤ 200,000
0 ≤
a
i
,
b
i
<
n
0 ≤
c
i
≤ 100,000
Output
答えの値を1行に出力せよ
Sample Input 1
4
0 1 3
1 2 5
1 3 2
Sample Output 1
23
Sample Input 2
6
0 2 5
2 1 1
2 3 10
3 5 4
3 4 2
Sample Output 2
111

Submitted solutions:

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

#define lint long long
#define P pair<int, int>
#define LLP pair<long long, long long>
#define REP(i, x, n) for(int i = (x), i##_len = (int)(n) ; i < i##_len ; ++i)
#define rep(i, n) for(int i = 0, i##_len = (int)(n) ; i < i##_len ; ++i)
#define repr(i, n) for(int i = (int)(n) - 1 ; i >= 0 ; --i)
#define SORT(x) sort((x).begin(), (x).end())
#define SORT_INV(x) sort((x).rbegin(), (x).rend())

#define int long long

const int IINF = 1e9 + 100;
const long long LLINF = 2e18 + 129;
const long long MOD = 1e9 + 7;
const int dx4[] = {1, 0, -1, 0}, dy4[] = {0, 1, 0, -1};
const int dx8[] = {1, 1, 0, -1, -1, -1, 0, 1}, dy8[] = {0, -1, -1, -1, 0, 1, 1, 1};
const double EPS = 1e-8;

struct unionFind{
    vector<int> par;
    int siz;

    void init(int N){
        par.resize(N);
        fill(par.begin(), par.end(), -1);
        siz = N;
        return;
    }

    int root(int X){
        if(par[X] < 0){
            return X;
        }
        return par[X] = root(par[X]);
    }

    bool unite(int X, int Y){
        X = root(X);
        Y = root(Y);

        if(X == Y){
            return false;
        }

        if(par[X] < par[Y]){
            swap(X, Y);
        }

        par[Y] += par[X];
        par[X] = Y;
        --siz;

        return true;
    }

    bool same(int X, int Y){
        return root(X) == root(Y);
    }

    int size(int X){
        return -par[root(X)];
    }
};

struct edge{
    int a, b;
    lint c;

    bool operator<(const edge & right) const {
        return c < right.c;
    }
};

signed main(){
    cin.tie(0);
    ios::sync_with_stdio(false);

    int n;
    cin >> n;

    vector<edge> edges(n - 1);
    rep(i, n - 1){
        int a, b;
        lint c;
        cin >> a >> b >> c;
        edges[i] = {a, b, c};
    }
    SORT(edges);

    unionFind uf;
    uf.init(n);

    lint ans = 0;
    for(auto e : edges){
        lint a = uf.size(e.a), b = uf.size(e.b);
        ans += a * b * e.c;
        uf.unite(e.a, e.b);
    }

    cout << ans << endl;

    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 9344
final_rank: 5

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


using namespace std;
//make -f ../makefile SRC=
/*
*/


//------------------------------------------------------------------------------
bool DEBUG = false;
const int INF = 1000000000;
//------------------------------------------------------------------------------
struct SEdge
{
    int v, w;
    int64_t c;

    bool operator<(const SEdge& e1) const
    {
        return c < e1.c;
    }

    SEdge(): v(-1), w(-1), c(-1) {}
    SEdge(int v1, int v2, int64_t cost): v(v1), w(v2), c(cost) {}
    void debug() const { printf("%d %d %ld\n", v, w, c); }
};

typedef vector<SEdge> SEdges;

//------------------------------------------------------------------------------
class QuickUnion
{
    public:
    int N;
    int M; // no. of E
    int64_t danger_level_sum;
    int* parent;
    int* count_; // no. of nodes rooted at n
    QuickUnion(int num): N(num), M(0)
    {
        danger_level_sum = 0;
        parent = new int[N]; // 0-based nodes
        count_ = new int[N];
        for (int n=0; n<N; n++) { parent[n]=n; count_[n]=1; }
    }

    ~QuickUnion() { delete[] parent; delete[] count_; }

    int size(int n) //<--------------------
    {
        int p = root(n);
        return count_[p];
    }

    bool connected()
    {
        return M+1 >= N;
    }

    bool unite(int n1, int n2, int64_t cost) //<---------- return true if action is successful
    {
        int r1 = root(n1);
        int r2 = root(n2);
        if (r1==r2) return false;
        M++; //<---------- for checking whether all are connected
        danger_level_sum += cost*count_[r1]*count_[r2];
        if (count_[r1] < count_[r2]) { parent[r1] = r2; count_[r2] += count_[r1]; }
        else { parent[r2] = r1; count_[r1] += count_[r2]; }
        return true;
    }

    bool find(int n1, int n2)
    {
        return root(n1)==root(n2);
    }

    int root(int node)
    {
        int n = node;
        while (n != parent[n])
        {
            parent[n] = parent[parent[n]]; // vs compression
            n = parent[n];
        }
        parent[node] = n;
        return n;
    }

    void debug() const
    {
        for (int n=0; n<N; n++) printf("node=%d, root=%d\n", n, parent[n]);
        printf("\n");
    }
};

//------------------------------------------------------------------------------
int64_t kruskal(int N, SEdges& E)
{
    sort(E.begin(), E.end());

    QuickUnion QU(N);
    for (SEdge e: E)
    {
        if (DEBUG) e.debug();
        if (QU.connected()) break;
        QU.unite(e.v, e.w, e.c);
    }
    return QU.danger_level_sum;
}

//------------------------------------------------------------------------------
void test()
{

}

//------------------------------------------------------------------------------
int main()
{
    //test(); return 0;
    //DEBUG = true;
    //--------------------------------------------------------------------------
    int T, N, M, v, w, num;
    int64_t c;
    //num = scanf("%d ", &T);
    //while (T--)
    //{
        num = scanf("%d ", &N);
        M = N-1;
        SEdges E(M);
        for (int m=0; m<M; ++m)
        {
            num = scanf("%d %d %ld ", &v, &w, &c);
            E[m] = SEdge(v, w, c);
        }
        printf("%ld\n", kruskal(N, E));
    //}
    //--------------------------------------------------------------------------
    return 0;
}
//------------------------------------------------------------------------------
accuracy: 1
time_ms: 40
memory_kb: 7752
final_rank: 3

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

//イテレーション
#define REP(i, n) for (ll i = 0; i < ll(n); i++)
#define REPD(i, n) for (ll i = n - 1; i >= 0; i--)
#define FOR(i, a, b) for (ll i = a; i <= ll(b); i++)
#define FORD(i, a, b) for (ll i = a; i >= ll(b); i--)
#define FORA(i, I) for (const auto& i : I)
// x:コンテナ
#define ALL(x) x.begin(), x.end()
#define SIZE(x) ll(x.size())
//定数
#define INF32 2147483647           // 2.147483647×10^{9}:32bit整数のinf
#define INF64 9223372036854775807  // 9.223372036854775807×10^{18}:64bit整数のinf
#define MOD 1000000007             //問題による
//略記
#define F first
#define S second
//出力(空白区切りで昇順に)
#define coutALL(x)                                                   \
    for (auto i = x.begin(); i != --x.end(); i++) cout << *i << " "; \
    cout << *--x.end() << endl;

// aをbで割る時の繰上げ,繰り下げ
ll myceil(ll a, ll b) { return (a + (b - 1)) / b; }
ll myfloor(ll a, ll b) { return a / b; }

ll root(vector<ll>& pars, ll x) {
    if(pars[x] == x) return x;
    return pars[x] = root(pars, pars[x]);
}

bool same(vector<ll>& pars, ll x, ll y) {
    ll rx = root(pars, x);
    ll ry = root(pars, y);
    return rx == ry;
}

ll size(vector<ll>& pars, vector<ll>& sizes, ll x) {
    return sizes[root(pars, x)];
}

void unite(vector<ll>& pars, vector<ll>& ranks, vector<ll>& sizes, ll x, ll y) {
    ll rx = root(pars, x);
    ll ry = root(pars, y);
    if(rx == ry) return;
    if(ranks[rx] < ranks[ry]) {
        pars[rx] = ry;
        sizes[ry] += sizes[rx];
    }else {
        pars[ry] = rx;
        if(ranks[rx] == ranks[ry]) ranks[ry]++;
        sizes[rx] += sizes[ry];
    }
    return;
}


int main() {
    //小数の桁数の出力指定
    // cout<<fixed<<setprecision(10);
    //入力の高速化用のコード
    // ios::sync_with_stdio(false);
    // cin.tie(nullptr);
    ll n;
    cin >> n;

    ll a,b,c;
    vector<tuple<ll,ll,ll>> ps;
    REP(i, n-1) {
        cin >> a >> b >> c;
        ps.push_back(make_tuple(c,a,b));
    }
    sort(ps.begin(), ps.end());
    vector<ll> pars;
    vector<ll> sizes;
    vector<ll> ranks;
    REP(i, n) {
        pars.push_back(i);
        sizes.push_back(1);
        ranks.push_back(0);
    }
    ll ans = 0;
    REP(i, n-1) {
        auto [c,a,b] = ps[i];
        ans += c * size(pars, sizes, a) * size(pars, sizes, b);
        unite(pars, ranks, sizes, a, b);
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 15188
final_rank: 17

code_snippet: #include <bits/stdc++.h>
//#include <atcoder/all>
//using namespace atcoder;
#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
using namespace std;
 
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<int, int> pii;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
 
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
 
 
#define FOR(i, s, n) for (int i = s; i < (int)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define trav(a, x) for (auto &a : x)
#define all(x) x.begin(), x.end()
 
#define MOD 1000000007
 
template<class T1, class T2> inline bool chmax(T1 &a, T2 b) {if (a < b) {a = b; return true;} return false;}
template<class T1, class T2> inline bool chmin(T1 &a, T2 b) {if (a > b) {a = b; return true;} return false;}
const double EPS = 1e-8, PI = acos(-1);
const double pi = 3.141592653589793238462643383279;
//ここから編集    
typedef string::const_iterator State;
ll GCD(ll a, ll b){
  return (b==0)?a:GCD(b, a%b);
}
ll LCM(ll a, ll b){
  return a/GCD(a, b) * b;
}
template< int mod >
struct ModInt {
  int x;
 
  ModInt() : x(0) {}
 
  ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
 
  ModInt &operator+=(const ModInt &p) {
    if((x += p.x) >= mod) x -= mod;
    return *this;
  }
 
  ModInt &operator-=(const ModInt &p) {
    if((x += mod - p.x) >= mod) x -= mod;
    return *this;
  }
 
  ModInt &operator*=(const ModInt &p) {
    x = (int) (1LL * x * p.x % mod);
    return *this;
  }
 
  ModInt &operator/=(const ModInt &p) {
    *this *= p.inverse();
    return *this;
  }
 
  ModInt operator-() const { return ModInt(-x); }
 
  ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
 
  ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
 
  ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
 
  ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
 
  bool operator==(const ModInt &p) const { return x == p.x; }
 
  bool operator!=(const ModInt &p) const { return x != p.x; }
 
  ModInt inverse() const {
    int a = x, b = mod, u = 1, v = 0, t;
    while(b > 0) {
      t = a / b;
      swap(a -= t * b, b);
      swap(u -= t * v, v);
    }
    return ModInt(u);
  }
 
  ModInt pow(int64_t n) const {
    ModInt ret(1), mul(x);
    while(n > 0) {
      if(n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }
 
  friend ostream &operator<<(ostream &os, const ModInt &p) {
    return os << p.x;
  }
 
  friend istream &operator>>(istream &is, ModInt &a) {
    int64_t t;
    is >> t;
    a = ModInt< mod >(t);
    return (is);
  }
 
  static int get_mod() { return mod; }
};
 
using modint = ModInt< 1000000007 >;
template< typename T >
struct Combination {
  vector< T > _fact, _rfact, _inv;
 
  Combination(int sz) : _fact(sz + 1), _rfact(sz + 1), _inv(sz + 1) {
    _fact[0] = _rfact[sz] = _inv[0] = 1;
    for(int i = 1; i <= sz; i++) _fact[i] = _fact[i - 1] * i;
    _rfact[sz] /= _fact[sz];
    for(int i = sz - 1; i >= 0; i--) _rfact[i] = _rfact[i + 1] * (i + 1);
    for(int i = 1; i <= sz; i++) _inv[i] = _rfact[i] * _fact[i - 1];
  }
 
  inline T fact(int k) const { return _fact[k]; }
 
  inline T rfact(int k) const { return _rfact[k]; }
 
  inline T inv(int k) const { return _inv[k]; }
 
  T P(int n, int r) const {
    if(r < 0 || n < r) return 0;
    return fact(n) * rfact(n - r);
  }
 
  T C(int p, int q) const {
    if(q < 0 || p < q) return 0;
    return fact(p) * rfact(q) * rfact(p - q);
  }
 
  T H(int n, int r) const {
    if(n < 0 || r < 0) return (0);
    return r == 0 ? 1 : C(n + r - 1, r);
  }
};
 
ll modpow(ll x, ll n, ll mod) {
  ll res = 1;
  while(n) {
    if(n&1) res = (res * x) % mod;
    x = (x * x) % mod;
    n >>= 1;
  }
  return res;
} 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
template<typename T> 
struct BIT{
  int N;
  std::vector<T> node;

  BIT(int n){
    N = n;
    node.resize(N+10);
  }

  /* a: 1-indexed */
  void add(int a, T x){
    for(int i=a; i<(int)node.size(); i += i & -i) node[i] += x;
  }

  /* [1, a] */
  T sum(int a){
    T res = 0;
    for(int x=a; x>0; x -= x & -x) res += node[x];
    return res;
  }

  /* [l, r] */
  T rangesum(int l, int r){
    return sum(r) - sum(l-1);
  }

  /* 
    a1+a2+...+aw >= valとなるような最小のwを返す
    @verify https://codeforces.com/contest/992/problem/E
  */
  int lower_bound(T val) {
    if(val < 0) return 0;

    int res = 0;
    int n = 1; 
    while (n < N) n *= 2;

    T tv=0;
    for (int k = n; k > 0; k /= 2) {
      if(res + k < N && node[res + k] < val){
        val -= node[res+k];
        res += k;
      }
    }
    return res+1; 
  }
};
struct UnionFind{
  std::vector<int> par;
  std::vector<int> siz;

  UnionFind(int sz_): par(sz_), siz(sz_) {
    for(int i=0; i<sz_; ++i) par[i] = i, siz[i] = 1;
  }

  void init(int sz_){
    par.resize(sz_);
    siz.resize(sz_);
    for(int i=0; i<sz_; ++i) par[i] = i, siz[i] = 1;
  }

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

  bool merge(int x, int y){
    x = root(x), y = root(y);
    if(x == y) return false;
    if(siz[x] < siz[y]) std::swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool issame(int x, int y){
    return root(x) == root(y);
  }

  int size(int x){
    return siz[root(x)];
  }
};
struct RollingHash {
    static const int base1 = 1007, base2 = 2009;
    static const int mod1 = 1000000007, mod2 = 1000000009;
    vector<long long> hash1, hash2, power1, power2;
    int n;
    // construct
    RollingHash(const string &S) {
        n = (int)S.size();
        hash1.assign(n+1, 0);
        hash2.assign(n+1, 0);
        power1.assign(n+1, 1);
        power2.assign(n+1, 1);
        for (int i = 0; i < n; ++i) {
            hash1[i+1] = (hash1[i] * base1 + S[i]) % mod1;
            hash2[i+1] = (hash2[i] * base2 + S[i]) % mod2;
            power1[i+1] = (power1[i] * base1) % mod1;
            power2[i+1] = (power2[i] * base2) % mod2;
        }
    }
    
    // get hash of S[left:right]
    inline pair<long long, long long> get(int l, int r) const {
        long long res1 = hash1[r] - hash1[l] * power1[r-l] % mod1;
        if (res1 < 0) res1 += mod1;
        long long res2 = hash2[r] - hash2[l] * power2[r-l] % mod2;
        if (res2 < 0) res2 += mod2;
        return {res1, res2};
    }
 
    inline pair<long long, long long> c_shift(int l) {
      auto h1 = get(0, l);
      auto h2 = get(l, n);
      return {(h1.first + h2.first * power1[l]) % mod1, (h1.second + h2.second * power2[l]) % mod2};
    }
 
    // get lcp of S[a:] and T[b:]
    inline int getLCP(int a, int b) const {
        int len = min((int)hash1.size()-a, (int)hash1.size()-b);
        int low = 0, high = len;
        while (high - low > 1) {
            int mid = (low + high) >> 1;
            if (get(a, a+mid) != get(b, b+mid)) high = mid;
            else low = mid;
        }
        return low;
    }
};
int main() {  
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(12);

  int n; cin >> n;
  vector<tuple<int, int, int>> g(n-1);
  REP(i,n-1) {
    int a, b, c; cin >> a >> b >> c;

    g[i] = {c, a, b};
  }
  sort(all(g));
  UnionFind uf(n);

  ll ans = 0;
  for(auto[c, a, b]: g) {
    ans += 1LL * c * uf.size(a) * uf.size(b);
    uf.merge(a, b);
  }
  cout << ans << endl;
  return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 6908
final_rank: 1

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

using namespace std;
using ll = long long;
using pii = pair<int, int>;

#define mp make_pair

struct UnionFindTree
{
	vector<int> par;
	vector<int> rank;
	vector<int> size;

	void init(int n)
	{
		par.resize(n);
		rank.resize(n);
		size.resize(n);
		for (int i = 0; i < n; i++)
		{
			par[i] = i;
			rank[i] = 0;
			size[i] = 1;
		}
	}
	int find(int x)
	{
		if (par[x] == x)
			return x;
		else
			return par[x] = find(par[x]);
	}
	void unite(int x, int y)
	{
		x = find(x);
		y = find(y);
		if (x == y)
			return;
		if (rank[x] < rank[y])
		{
			par[x] = y;
			size[y] += size[x];
		}
		else
		{
			par[y] = x;
			if (rank[x] == rank[y])
				rank[x]++;
			size[x] += size[y];
		}
	}
	bool same(int x, int y)
	{
		return find(x) == find(y);
	}
	int getSize(int x)
	{
		x = find(x);
		return size[x];
	}
};

int main()
{
	ll c, ans;
	int a, b, n;
	while (cin >> n)
	{
		vector<pair<ll, pii>> room;
		for (int i = 0; i < n-1; i++)
		{
			cin >> a >> b >> c;
			room.push_back(mp(c,mp(a,b)));
		}
		sort(room.begin(), room.end());
		UnionFindTree dungeon;
		dungeon.init(n);
		ans = 0;
		for (int i = 0; i < n-1; i++)
		{
			a = room[i].second.first;
			b = room[i].second.second;
			c = room[i].first;
			ans += c * dungeon.getSize(a) * dungeon.getSize(b);
			dungeon.unite(a, b);
		}
		cout << ans << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 8212
final_rank: 12

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <set>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>
#include <sstream>
#include <bitset>
#include <complex>
#include <chrono>
#include <cassert>

class UnionFind {
	std::vector<int> parent;
public:
	UnionFind(const int size) :parent(size, -1) {};
	int find(const int a) {
		return parent[a] < 0 ? a : parent[a] = find(parent[a]);
	}
	int size(const int a) {
		return -parent[find(a)];
	}
	void unite(int a, int b) {
		a = find(a);
		b = find(b);
		if (a == b) return;
		if (parent[a] > parent[b]) std::swap(a, b);
		parent[a] += parent[b];
		parent[b] = a;
	}
};
int main() {
	int n; std::cin >> n;
	std::vector<std::tuple<int, int, int>> edges(n - 1);
	for (auto& [a, b, c] : edges) {
		std::cin >> a >> b >> c;
	}
	std::sort(edges.begin(), edges.end(), [](const std::tuple<int, int, int> a, const std::tuple<int, int, int> b) {return std::get<2>(a) < std::get<2>(b); });
	UnionFind uft(n);
	long long int result{ 0 };
	for (const auto [a, b, c] : edges) {
		const long long int side_a = uft.size(a);
		const long long int side_b = uft.size(b);
		result += c * side_a * side_b;
		uft.unite(a, b);
	}
	std::cout << result << '\n';
}
accuracy: 1
time_ms: 100
memory_kb: 6244
final_rank: 7

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <set>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>
#include <sstream>
#include <bitset>
#include <complex>
#include <chrono>
#include <cassert>

class UnionFind {
	std::vector<int> parent;
public:
	UnionFind(const int size) :parent(size, -1) {};
	int find(const int a) {
		return parent[a] < 0 ? a : parent[a] = find(parent[a]);
	}
	int size(const int a) {
		return -parent[find(a)];
	}
	void unite(int a, int b) {
		a = find(a);
		b = find(b);
		if (a == b) return;
		if (parent[a] > parent[b]) std::swap(a, b);
		parent[a] += parent[b];
		parent[b] = a;
	}
};
int main() {
	int n; std::cin >> n;
	std::vector<std::tuple<int, int, int>> edges(n - 1);
	for (auto& [a, b, c] : edges) {
		std::cin >> a >> b >> c;
	}
	std::sort(edges.begin(), edges.end(), [](const std::tuple<int, int, int> a, const std::tuple<int, int, int> b) {return std::get<2>(a) < std::get<2>(b); });
	UnionFind uft(n);
	long long int result{ 0 };
	for (const auto [a, b, c] : edges) {
		const long long int side_a = uft.size(a);
		const long long int side_b = uft.size(b);
		const auto sum = side_a + side_b;
		result += c * (sum * (sum - 1) / 2 - side_a * (side_a - 1) / 2 - side_b * (side_b - 1) / 2);
		uft.unite(a, b);
	}
	std::cout << result << '\n';
}
accuracy: 1
time_ms: 100
memory_kb: 6212
final_rank: 6

code_snippet: #include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#include<string>
#include<cmath>
#include<cstring>
#include<queue>
#include<map>
#include<climits>
#include<set>
#include<tuple>


using namespace std;
typedef pair<int, int> pii;
typedef long long int ll;
typedef pair<ll, ll> pll;
int dx[4] = { 1,0,0,-1 };
int dy[4] = { 0,1,-1,0 };

#define ARRAY_MAX 100005 

const int INF = 1e9 + 7;
const int MOD = 1e9 + 7;

typedef tuple<int, int, int> tpl;

//繋げる方向を一方向にする
typedef struct union_find {

	vector<ll> pa;//親
	vector<ll> ra;//木の深さ
	vector<ll> siz;
	//n要素で初期化
	void init(ll n) {
		pa.resize(n);
		ra.resize(n);
		siz.resize(n);
		for (ll i = 0; i < n; i++) {
			pa[i] = i;/*各ノードに番号を振る,この時par[x]=xとなる時は木の根となる*/
			ra[i] = 0LL;/*各ノード自体の高さは0*/
			siz[i] = 1LL;
		}
	}
	//木の根を求める
	ll find(ll x) {
		if (pa[x] == x) {
			return x;/*根ならそのノードの番号を返す*/
		}
		else {
			return pa[x] = find(pa[x]);/*根でないならさらにノードの根を探す*/
		}
	}

	//xとyの属する集合を併合する
	void unite(ll x, ll y) {
		x = find(x);//xの根の番号を探す
		y = find(y);//yの根の番号を探す
		if (x == y) {//一致すればつながっている
			return;
		}
		pa[y] = x;
		siz[x] += siz[y];
	}

	//xとyが同じ集合に属するか判定
	bool same(ll x, ll y) {
		return find(x) == find(y);//同じ集合なら1、違うなら0が返る
	}
}UF;

int main() {

	ll n;
	cin >> n;
	vector<tpl> vec(n-1);
	for (int i = 0; i < n-1; i++)
	{
		int a, b, c;
		cin >> a >> b >> c;
		vec[i] = tpl(c, a, b);
	}

	UF tree;
	tree.init(n);
	
	sort(vec.begin(), vec.end());

	ll ans = 0;

	for (int i = 0; i < n-1; i++)
	{
		ll a, b, c;
		tie(c, a, b) = vec[i];
		a = tree.find(a);
		b = tree.find(b);
		if (!tree.same(a, b))
		{
			ans += 1LL * c * tree.siz[a] * tree.siz[b];
			tree.unite(a, b);
		}
	}
	cout << ans << endl;
}
accuracy: 1
time_ms: 130
memory_kb: 9960
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<ll ,P> P3;
const ll MOD = ll(1e9+7);
const int IINF = INT_MAX;
const ll LLINF = LLONG_MAX;
const int MAX_N = int(1e5 + 5);
const double EPS = 1e-6;
const int di[] = {0, 1, 0, -1}, dj[] = {1, 0, -1, 0};
#define REP(i, n) for (int i = 0; i < n; i++)
#define REPR(i, n) for (int i = n; i >= 0; i--)
#define SORT(v) sort((v).begin(), (v).end())
#define ALL(v) (v).begin(), (v).end()

struct UnionFindTree {
    vector<int> par;
    vector<int> rank;
    vector<int> siz;

    void init(int n) {
        par.resize(n);
        rank.resize(n);
        siz.resize(n);
        for (int i = 0; i < n; i++) {
            par[i] = i;
            rank[i] = 0;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) {
            return x;
        } else {
            return par[x] = find(par[x]);
        }
    }
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        if (rank[x] < rank[y]) swap(x, y);
        if (rank[x] == rank[y]) rank[x]++;
        par[y] = x;
        siz[x] += siz[y];
    }
    bool is_same(int x, int y) {
        return find(x) == find(y);
    }
    int size(int x) {
        x = find(x);
        return siz[x];
    }
};

int main() {
    int n;
    vector<P3> es;
    cin >> n;
    REP(i,n-1){
        ll a, b, c;
        cin >> a >> b >> c;
        es.push_back({c,{a,b}});
    }
    sort(ALL(es));
    UnionFindTree g;
    g.init(n);
    ll ans = 0;
    REP(i,n){
        ll a, b, c;
        a = es[i].second.first;
        b = es[i].second.second;
        c = es[i].first;
        ans += c*ll(g.size(a))*ll(g.size(b));
        g.unite(a,b);
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 9808
final_rank: 15

code_snippet: #include <stdio.h>
#include <queue>
#include <utility>
using namespace std;
typedef pair<int,int> pi;
typedef long long int ll;
#define F first
#define S second
const int N=2e5+10;
int p[N],sz[N];
int find(int n){return p[n]==n?n:p[n]=find(p[n]);}
int main(){
    int n,a,b,c;
    pair<int,pi> temp;
    ll ans=0;
    priority_queue<pair<int,pi>,vector<pair<int,pi>>,greater<pair<int,pi>>>pq;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        p[i]=i;
        sz[i]=1;
    }
    for(int i=1;i<n;i++){
        scanf("%d%d%d",&a,&b,&c);
        pq.push({c,{a,b}});
    }
    while(!pq.empty()){
        temp=pq.top();
        pq.pop();
        a=find(temp.S.F);
        b=find(temp.S.S);
        ans+=(ll)sz[a]*(ll)sz[b]*(ll)temp.F;
        sz[a]+=sz[b];
        p[b]=a;
    }
    printf("%lld\n",ans);
}
accuracy: 1
time_ms: 60
memory_kb: 7028
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout<<#x" = "<<((x))<<endl
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

struct UF{
    int n;
    //正だったらその頂点の親,負だったら根で連結成分の個数
    vector<int> d;
    UF() {}
    UF(int N):n(N), d(N,-1){}
    int root(int v){
        if(d[v]<0) return v;
        return d[v]=root(d[v]);
    }
    bool unite(int X,int Y){
        X=root(X); Y=root(Y);
        if(X==Y) return false;
        if(size(X) < size(Y)) swap(X,Y);
        d[X]+=d[Y];
        d[Y]=X;
        return true;
    }
    int size(int v){ return -d[root(v)]; }
    bool same(int X,int Y){ return root(X)==root(Y); }
};

using pi = pair<int,int>;
using edge = pair<int,pi>;

int main(){
    int n;
    cin >>n;

    vector<edge> e(n-1);
    rep(i,n-1){
        int a,b,c;
        cin >>a >>b >>c;
        e[i] = {c,{a,b}};
    }
    sort(all(e));

    UF uf(n);
    ll ans = 0;
    rep(i,n-1){
        ll c = e[i].fi;
        int u = e[i].se.fi, v = e[i].se.se;

        ans += c*uf.size(u)*uf.size(v);
        uf.unite(u,v);
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 6000
final_rank: 8

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

using namespace std;

#define int long long

struct UF {
  vector<int> data;
  UF(int n):data(n, -1){}
  int find(int x) {
    if(data[x] < 0) return x;
    return data[x] = find(data[x]);
  }
  int size(int x) {
    return -data[find(x)];
  }
  bool same(int x, int y) {
    return find(x) == find(y);
  }
  void unite(int x, int y) {
    x = find(x), y = find(y);
    if(x == y) return;
    if(data[x] > data[y]) swap(x, y);
    data[x] += data[y];
    data[y] = x;
  }
};

struct edge {
  int u, v, w;
  edge(){}
  edge(int u, int v, int w):u(u), v(v), w(w){}
  bool operator < (const edge& e) const {
    return w < e.w;
  }
};

signed main() {
  int n;
  cin >> n;
  vector<edge> es;
  for(int i = 0; i < n-1; ++i) {
    int a, b, c;
    cin >> a >> b >> c;
    es.emplace_back(a, b, c);
  }
  sort(es.begin(), es.end());
  UF uf(n);
  int ans = 0;
  for(edge& e : es) {
    int x = uf.find(e.u), y = uf.find(e.v);
    if(x == y) continue;
    ans += e.w*uf.size(x)*uf.size(y);
    uf.unite(x, y);
  }
  
  cout << ans << endl;

  return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 9104
final_rank: 13

code_snippet: #include <bits/stdc++.h>
#define GET_MACRO(_1,_2,_3,_4,_5,NAME,...) NAME
#define pr(...) GET_MACRO(__VA_ARGS__,pr5,pr4,pr3,pr2,pr1)(__VA_ARGS__)
#define pr1(a) (#a)<<"="<<(a)
#define pr2(a,b) pr1(a)<<", "<<pr1(b)
#define pr3(a,b,c) pr2(a,b)<<", "<<pr1(c)
#define pr4(a,b,c,d) pr3(a,b,c)<<", "<<pr1(d)
#define pr5(a,b,c,d,e) pr4(a,b,c,d)<<", "<<pr1(e)
#define int long long
#define double long double
using namespace std;
const int N = 100010;
const int INF = 1LL<<55;
const int mod = (1e9)+7;
const double EPS = 1e-8;
const double PI = 6.0 * asin(0.5);
typedef pair<int,int> P;
typedef long long ll;
template<class T> T Max(T &a,T b){return a=max(a,b);}
template<class T> T Min(T &a,T b){return a=min(a,b);}
ostream& operator<<(ostream& o,P p){return o<<"("<<p.first<<","<<p.second<<")";}
istream& operator>>(istream& i,P &p){return i>>p.first>>p.second;}
ostream& operator<<(ostream& o,vector<auto> &a){int i=0;for(auto t:a)o<<(i++?" ":"")<<t;return o;}
istream& operator>>(istream& i,vector<auto> &a){for(auto &t:a)i>>t;return i;}
void prArr(auto a,string s=" "){int i=0;for(auto t:a)cout<<(i++?s:"")<<t;cout<<endl;}

class UF{
public:
  int V;
  vector<int> par,rnk,sz;
  UF(){}
  UF(int V):V(V),par(V),rnk(V,0),sz(V,1){for(int i=0;i<V;i++)par[i]=i;}
  
  int find(int x){
    assert(x < V);
    if(par[x]==x)return x;
    return par[x]=find(par[x]);
  }
  
  void unite(int x,int y){
    x=find(x), y=find(y);
    if(x==y)return;
    if(rnk[x]<rnk[y])par[x]=y, sz[y] += sz[x];
    else{
      par[y]=x;
      sz[x] += sz[y];
      if(rnk[x]==rnk[y])rnk[x]++;
    }
  }

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

  int size(int x){return sz[find(x)];}
};

signed main(){
  int n;
  cin>>n;
  typedef tuple<int,int,int> T;
  vector<T> edge;
  for(int i=0;i<n-1;i++){
    int a,b,c;
    cin>>a>>b>>c;
    edge.push_back(T(c,a,b));
  }

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

  int ans = 0;
  UF uf(n);
  for(auto e:edge){
    int c,a,b; tie(c,a,b) = e;
    ans += c * uf.size(a) * uf.size(b);
    uf.unite(a,b);
  }

  cout<<ans<<endl;
  
  return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 12252
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
struct Kruskal{

  struct UnionFind{
    Int n;
    vector<Int> r,p;
    UnionFind(){}
    UnionFind(Int sz):n(sz),r(sz,1),p(sz,0){iota(p.begin(),p.end(),0);}
    Int find(Int x){
      return (x==p[x]?x:p[x]=find(p[x]));
    }
    bool same(Int x,Int y){
      return find(x)==find(y);
    }
    void unite(Int x,Int y){
      x=find(x);y=find(y);
      if(x==y) return;
      if(r[x]<r[y]) swap(x,y);
      r[x]+=r[y];
      p[y]=x;
    }
  };
  
  struct edge{
    Int from,to,cost,used;
    edge(){}
    edge(Int from,Int to,Int cost):
      from(from),to(to),cost(cost),used(0){}
    bool operator<(const edge& e) const{
      return cost<e.cost;
    }
  };

  Int n;
  vector<edge> edges;

  Kruskal(){}
  Kruskal(Int sz):n(sz){}
  
  void add_edge(Int u,Int v,Int c){
    edges.emplace_back(u,v,c);
  }

  void input(Int m,Int offset=0){
    Int a,b,c;
    for(Int i=0;i<m;i++){
      cin>>a>>b>>c;
      add_edge(a+offset,b+offset,c);
    }
  }
  
  Int build(){
    sort(edges.begin(),edges.end());
    UnionFind uf(n+1);
    Int res=0;
    for(auto &e:edges){
      if(!uf.same(e.from,e.to)){
	res+=e.cost*uf.r[uf.find(e.from)]*uf.r[uf.find(e.to)];
	uf.unite(e.from,e.to);
	e.used=1;
      }
    }
    return res;
  }
};
signed main(){  
  cin.tie(0);
  ios::sync_with_stdio(0);
  Int n;
  cin>>n;
  Kruskal G(n);
  G.input(n-1);
  cout<<G.build()<<endl;
  return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 12196
final_rank: 9

code_snippet: #include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
 
using namespace std;
 
#define FOR(i,k,n) for(int i=(k); i<(int)(n); ++i)
#define REP(i,n) FOR(i,0,n)
#define FORIT(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
 
template<class T> void debug(T begin, T end){ for(T i = begin; i != end; ++i) cerr<<*i<<" "; cerr<<endl; }
inline bool valid(int x, int y, int W, int H){ return (x >= 0 && y >= 0 && x < W && y < H); }
 
typedef long long ll;
const int INF = 100000000;
const double EPS = 1e-8;
const int MOD = 1000000007;
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
 
struct UnionFind {
  vector<int> data;
  UnionFind(int N) : data(N, -1) { }
  bool uni(int x, int y) {
    x = root(x); y = root(y);
    if (x != y) {
      if (data[x] > data[y]) swap(x, y);
      data[x] += data[y]; data[y] = x;
    }
    return x != y;
  }
  bool find(int x, int y) {
    return root(x) == root(y);
  }
  int root(int x) {
    return data[x] < 0 ? x : data[x] = root(data[x]);
  }
  int size(int x) {
    return -data[root(x)];
  }
};
 
struct edge{
  int src, dst, cost;
  edge(int s, int d, int c) : src(s), dst(d), cost(c) {}
  edge() {}
  bool operator< (const edge& e) const {
    return cost < e.cost;
  }
};
 
int main(){
  int N;
  cin>>N;
  vector<edge> v(N - 1);
  REP(i, N - 1){
    int a, b, c;
    scanf("%d %d %d", &a, &b, &c);
    v[i] = edge(a, b, c);
  }
  UnionFind uf(N);
  sort(v.begin(), v.end());
  ll ans = 0;
  REP(i, N - 1){
    ans += (ll)uf.size(v[i].src) * uf.size(v[i].dst) * v[i].cost;
    uf.uni(v[i].src, v[i].dst);
  }
  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 6044
final_rank: 2

code_snippet: #include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;

struct UnionFind {
	vector<int> data;
	UnionFind(int size) : data(size, -1) { }
	bool unionSet(int x, int y) {
		x = root(x); y = root(y);
		if (x != y) {
			if (data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	int root(int x) {
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x) {
		return -data[root(x)];
	}
};



int main() {
	int N;cin>>N;
	vector<pair<unsigned long long int, pair<int, int>>>edges;
	for (int i = 0; i < N - 1; ++i) {
		int a,b,c;cin>>a>>b>>c;
		pair<unsigned long long int,pair<int,int>> edge(make_pair(c,make_pair(a,b)));
		edges.push_back(edge);
	}
	sort(edges.begin(),edges.end());
	UnionFind uf(N);
	unsigned long long int ans=0;
	for (auto edge : edges) {
		int a=edge.second.first;
		int b=edge.second.second;
		unsigned long long int c=edge.first;
		ans+=c*uf.size(a)*uf.size(b);
		uf.unionSet(a,b);
	}
	cout<<ans<<endl;
	return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 7000
final_rank: 11

code_snippet: #include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;

struct UnionFind {
	vector<int> data;
	UnionFind(int size) : data(size, -1) { }
	bool unionSet(int x, int y) {
		x = root(x); y = root(y);
		if (x != y) {
			if (data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	int root(int x) {
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x) {
		return -data[root(x)];
	}
};



int main() {
	int N;cin>>N;
	vector<pair<unsigned long long int, pair<int, int>>>edges;
	for (int i = 0; i < N - 1; ++i) {
		int a,b,c;cin>>a>>b>>c;
		pair<unsigned long long int,pair<int,int>> edge(make_pair(c,make_pair(a,b)));
		edges.push_back(edge);
	}
	sort(edges.begin(),edges.end());
	UnionFind uf(N);
	unsigned long long int ans=0;
	for (auto edge : edges) {
		int a=edge.second.first;
		int b=edge.second.second;
		unsigned long long int c=edge.first;
		ans+=uf.size(a)*uf.size(b)*c;
		uf.unionSet(a,b);
	}
	cout<<ans<<endl;
	return 0;
}
accuracy: 0.9918032786885246
time_ms: 170
memory_kb: 6888
final_rank: 20

code_snippet: #include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;

struct UnionFind {
	vector<int> data;
	UnionFind(int size) : data(size, -1) { }
	bool unionSet(int x, int y) {
		x = root(x); y = root(y);
		if (x != y) {
			if (data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	int root(int x) {
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x) {
		return -data[root(x)];
	}
};



int main() {
	int N;cin>>N;
	vector<pair<long long int, pair<int, int>>>edges;
	for (int i = 0; i < N - 1; ++i) {
		int a,b,c;cin>>a>>b>>c;
		pair<long long int,pair<int,int>> edge(make_pair(c,make_pair(a,b)));
		edges.push_back(edge);
	}
	sort(edges.begin(),edges.end());
	UnionFind uf(N);
	long long int ans=0;
	for (auto edge : edges) {
		int a=edge.second.first;
		int b=edge.second.second;
		long long int c=edge.first;
		ans+=uf.size(a)*uf.size(b)*c;
		uf.unionSet(a,b);
	}
	cout<<ans<<endl;
	return 0;
}
accuracy: 0.9918032786885246
time_ms: 140
memory_kb: 7004
final_rank: 19

code_snippet: #include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 200000


struct Info{
	bool operator<(const struct Info &arg) const{
		return cost < arg.cost;
	}
	ll from,to,cost;
};

Info info[NUM];
int N;
ll boss[NUM],height[NUM],member_num[NUM];

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[x] > height[y]){

		boss[boss_y] = boss_x;
		member_num[boss_x] += member_num[boss_y];

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;
		member_num[boss_y] += member_num[boss_x];

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		member_num[boss_x] += member_num[boss_y];
		height[x]++;
	}
}

int main(){

	scanf("%d",&N);

	for(int i = 0; i < N-1; i++){
		scanf("%lld %lld %lld",&info[i].from,&info[i].to,&info[i].cost);
	}

	sort(info,info+N-1);

	for(int i = 0; i < N; i++){
		boss[i] = i;
		height[i] = 0;
		member_num[i] = 1;
	}

	ll ans = 0;

	for(int i = 0; i < N-1; i++){
		ans += member_num[get_boss(info[i].from)]*member_num[get_boss(info[i].to)]*info[i].cost;
		unite(info[i].from,info[i].to);
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 12632
final_rank: 10

code_snippet: #include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 200000


struct Info{
	bool operator<(const struct Info &arg) const{
		return cost < arg.cost;
	}
	ll from,to,cost;
};

Info info[NUM];
int N;
int boss[NUM],height[NUM],member_num[NUM];

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[x] > height[y]){

		boss[boss_y] = boss_x;
		member_num[boss_x] += member_num[boss_y];

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;
		member_num[boss_y] += member_num[boss_x];

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		member_num[boss_x] += member_num[boss_y];
		height[x]++;
	}
}

int main(){

	scanf("%d",&N);

	for(int i = 0; i < N-1; i++){
		scanf("%lld %lld %lld",&info[i].from,&info[i].to,&info[i].cost);
	}

	sort(info,info+N-1);

	for(int i = 0; i < N; i++){
		boss[i] = i;
		height[i] = 0;
		member_num[i] = 1;
	}

	ll ans = 0;

	for(int i = 0; i < N-1; i++){
		ans += member_num[get_boss(info[i].from)]*member_num[get_boss(info[i].to)]*info[i].cost;
		unite(info[i].from,info[i].to);
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 0.9918032786885246
time_ms: 60
memory_kb: 10292
final_rank: 18