#pragma GCC optimize("O3,unroll-loops")
#include <bits/stdc++.h>
#define ll long long
#define sti string
#define itachi ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define maxn 500005
#define fi first
#define se second
#define ldb long double
using namespace std;

int n;

int32_t color[maxn], sz[maxn];
bool banned[maxn];
int32_t cnt[maxn];
int32_t delta_only[maxn], delta_all[maxn];
int32_t delta_only_inside[maxn], delta_all_inside[maxn];
vector<pair<int32_t, int32_t>> adj[maxn];

long long ans=0;
int sum_only = 0;
int sum_only_inside = 0;
vector<int32_t> usedDelta, usedInside;
int current_root = 0;

void orient_color(int u, int p) {
    for (auto [v, w] : adj[u]) {
        if (v == p || banned[v]) continue;
        color[v] = w;
        orient_color(v, u);
    }
}

void get_sz(int u, int p) {
    sz[u] = 1;
    for (auto [v, w] : adj[u]) {
        if (v != p && !banned[v]) {
            get_sz(v, u);
            sz[u] += sz[v];
        }
    }
}

void countChild(int u, int p) {
    sz[u] = 1;
    bool first = false;
    if (u != current_root) first = (++cnt[color[u]] == 1);
    for (auto [v,w] : adj[u]) {
        if (v == p || banned[v]) continue;
        countChild(v, u);
        sz[u] += sz[v];
    }
    if (u != current_root) {
        if (first) {
            sum_only += sz[u];
            if (delta_all[color[u]] == 0) usedDelta.push_back(color[u]);
            delta_all[color[u]] += sz[u];
            delta_only[color[u]] += sz[u];
        }
        else if (cnt[color[u]] == 2) { 
            sum_only -= sz[u];
            delta_only[color[u]] -= sz[u];
        }
        --cnt[color[u]];
    }
}

int find_cen(int u, int p, int S) {
    for (auto [v,w] : adj[u]) {
        if (v != p && !banned[v] && sz[v] > S / 2) {
            return find_cen(v, u, S);
        }
    }
    return u;
}

void cntInside(int u, int p) {
    bool first = (++cnt[color[u]] == 1);

    if (first) {
        sum_only_inside += sz[u];
        if (delta_all_inside[color[u]] == 0) usedInside.push_back(color[u]);
        delta_only_inside[color[u]] += sz[u];
        delta_all_inside[color[u]] += sz[u];
    }
    else if (cnt[color[u]] == 2) { 
        sum_only_inside -= sz[u];
        delta_only_inside[color[u]] -= sz[u];
    }

    for (auto [v,w] : adj[u]) {
        if (v == p || banned[v]) continue;
        cntInside(v, u);
    }

    --cnt[color[u]];
}

void addRootPaths(int u, int p, int distinct) {
    bool first = (++cnt[color[u]] == 1);
    if (first) distinct++;
    else if (cnt[color[u]] == 2) distinct--;

    ans += 2 * distinct;

    for (auto [v, w] : adj[u]) {
        if (v == p || banned[v]) continue;
        addRootPaths(v, u, distinct);
    }
    --cnt[color[u]];
}

void dfs(int u, int p, int edge_color, int only_cur, int all_cur, int only_out, int distinctlen, int ver_out) {
    int C = edge_color;
    bool first = (++cnt[C] == 1);

    if (first) {
        distinctlen++;
        all_cur += delta_all[C] - delta_all_inside[C];
        only_cur += delta_only[C] - delta_only_inside[C];
    }
    else if (cnt[C] == 2) {
        distinctlen--;
        all_cur -= delta_all[C] - delta_all_inside[C];
    }

    ans += distinctlen * ver_out - all_cur - only_cur + only_out;

    for (auto [v,w] : adj[u]) {
        if (v == p || banned[v]) continue;
        dfs(v, u, w, only_cur, all_cur, only_out, distinctlen, ver_out);
    }

    --cnt[C];
}

void solve(int u) {
    get_sz(u, 0);

    int root = find_cen(u, 0, sz[u]);
    orient_color(root, 0);
    
    current_root = root;
    sum_only = 0;
    countChild(root, 0);
    int all_node = sz[root];
    
    for (auto [v,w] : adj[root]) {
        if (banned[v]) continue;
        addRootPaths(v, root, 0);
    }

    for (auto [v,w] : adj[root]) {
        if (banned[v]) continue;

        sum_only_inside = 0;
        cntInside(v, root);
        int ver_out = all_node - sz[v] - 1;
        int only_out = sum_only - sum_only_inside;

        dfs(v, root, w, 0, 0, only_out, 0, ver_out);

        for (int c : usedInside) {
            delta_all_inside[c] = 0;
            delta_only_inside[c]=0;
        }
        usedInside.clear();
    }

    banned[root] = 1;
    for (int c : usedDelta) {
        delta_all[c] = 0;
        delta_only[c]=0;
    }
    usedDelta.clear();
    for (auto [v,w] : adj[root]) {
        if (!banned[v]) solve(v);
    }
}

signed main()
{
    itachi
    cin>>n;
    for (int i = 1; i < n; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        adj[u].push_back({v,w});
        adj[v].push_back({u,w});
    }

    solve(1);
    cout << ans / 2;
    return 0;
}