#include <bits/stdc++.h>
#include <bits/stdtr1c++.h>
#include <ext/pb_ds/assoc_container.hpp>
#define ll long long
#define pb push_back
#define endl "\n"
#define amfetamin ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); cerr.tie(0);
#define ordered_set tree<int,null_type,less_equal<int>,rb_tree_tag,tree_order_statistics_node_update>
using namespace std;
const int N = 3e5 + 5;
list <pair<int,int>> adj[N];
map <tuple<int,int,int>, ll> mp;
int koji[N];
int co[N][3];
pair<int,int> tour[2 * N - 1];
bool visited[N] = { };
int segtree[4 * N - 2];
int depth[N];
int pre[N];
int ct = 0;
void dfs(int n)
{
    visited[n] = true;
    pre[n] = ct;
    tour[ct].first = n;
    tour[ct].second = depth[n];
    ct++;
    for (auto it = adj[n].begin(); it != adj[n].end(); ++it)
    {
        int v = it->first;
        if (!visited[v])
        {
        depth[v] = depth[n] + 1;
        co[v][0] = co[n][0];
        co[v][1] = co[n][1];
        co[v][2] = co[n][2];
        co[v][it->second]++;

        dfs(v);
        tour[ct].first = n;
        tour[ct].second = depth[n];
        ct++;
        }
    }
}
int rmq(int l, int r, int n)
{
    l += n;
    r += n;
    int mn = INT_MAX-1;
    int pos;
      while (l < r)
      {
         if (l % 2 == 1)
         {
             if (segtree[l] < mn)
             {
                 mn = segtree[l];
                 pos = l;
             }
             l++;
         }
         if (r % 2 == 1)
         {
             r--;
             if (segtree[r] < mn)
             {
                 mn = segtree[r];
                 pos = r;
             }
         }
         r /= 2;
         l /= 2;
       }
    return pos;
}
int index(int pos, int n)
{
    int ind = pos;
    while (ind < n)
    {
        if (segtree[ind * 2] == segtree[ind]) ind = ind * 2;
        else ind = ind * 2 + 1 ;
    }
    return ind - n;
}

int main()
{
amfetamin;
bool b1 = true;
int n;
cin >> n;
for (int i = 0; i < n - 1; i++)
{
    int a,b,d;
    char c;
    cin >> a >> b >> c;
    if (c == 'S')
        d = 0;
    if (c == 'I')
        d = 1;
    if (c == 'O')
        d = 2;
    a--, b--;
    if (a > b)
        swap(a, b);
    if (b != a + 1)
        b1 = false;

    koji[a] = d;
    adj[a].push_back({b, d});
    adj[b].push_back({a, d});
}
if (b1)
{
    int g[3] = { };
    for (int i = 0; i < n; i++)
    {
        int mn = min(min(g[0], g[1]), g[2]);
        tuple <int,int,int> tp = make_tuple(g[0] - mn, g[1] - mn, g[2] - mn);
        auto it = mp.find(tp);
        if (it == mp.end())
            mp.insert({tp, 1});
        else
            it->second++;
        g[koji[i]]++;
    }
    ll sol = 0;
    for (auto it = mp.begin(); it != mp.end(); ++it)
    {
        ll cur = it->second;
        sol += cur*(cur-1)/2;
    }
    cout << sol;
}
else
{
    depth[0] = 1;
    dfs(0);
    int sz = 2 * n - 1;
    for (int i = 0; i < sz; i++)
        segtree[sz + i] = tour[i].second;
    for (int i = sz - 1; i >= 1; i--)
        segtree[i] = min(segtree[2 * i], segtree[2 * i + 1]);
    ll sol = 0;
    for (int i = 0; i < n; i++)
        for (int j = i + 1; j < n; j++)
    {
        int l = pre[i]; int r = pre[j]; if (l > r) swap (l, r);
        int lca = tour[index(rmq(l, r + 1, sz), sz)].first;
        if (lca != i && lca != j)
        {
            int ct1 = co[i][0] + co[j][0] - 2 * co[lca][0];
            int ct2 = co[i][1] + co[j][1] - 2 * co[lca][1];
            int ct3 = co[i][2] + co[j][2] - 2 * co[lca][2];
            if (ct1 == ct2 && ct2 == ct3)
                sol++;
        }
        else
        {
            int x = i;
            int y = j;
            if (y == lca)
                swap(x, y);
            int ct1 = co[y][0] - co[x][0];
            int ct2 = co[y][1] - co[x][1];
            int ct3 = co[y][2] - co[x][2];
            if (ct1 == ct2 && ct2 == ct3)
                sol++;
        }
    }
    cout << sol;
}

}