int read () { char c = getchar(); int x = 0; while (c<'0'||c>'9') c = getchar(); while ('0'<=c&&c<='9') { x = x*10+c-'0'; c = getchar(); } return x; }
int n,m,k; const int maxn = 1e6; map<int,int> E[maxn]; int C[maxn]; int ind[maxn]; int cnt[maxn];
struct Node { int x; int y; };
int f[maxn]; int sz[maxn];
int _find (int x) { if (f[x]==x) return x; f[x] = _find(f[x]); return f[x]; }
queue<Node> q;
void _merge (int a, int b) { int fa = _find(a); int fb = _find(b); if (fa==fb) return; if (sz[fa]<sz[fb]) swap(fa,fb); map<int,int>::iterator It; for (It=E[fb].begin();It!=E[fb].end();It++) { int c = It->first; int to = It->second; if (E[fa][c]) q.push({E[fa][c],to}); else E[fa][c] = to; } f[fb] = fa; sz[fa] += sz[fb]; }
int main () { n = read(); m = read(); k = read(); for (int i=1;i<=n;i++) { f[i] = i; sz[i] = 1; } for (int i=1;i<=m;i++) { int u = read(); int v = read(); int w = read(); if (E[v][w]) q.push({E[v][w],u}); else E[v][w] = u; } while (!q.empty()) { int x = q.front().x; int y = q.front().y; q.pop(); _merge(x,y); } for (int i=1;i<=n;i++) { f[i] = _find(i); cnt[f[i]]++; } long long ans = 0; for (int i=1;i<=n;i++) { ans += 1ll*cnt[i]*(cnt[i]-1)/2; } cout<<ans<<endl; }