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


int n;
typedef pair<int,int> Sio;
vector <vector <pair <int,Sio> > > Graph;

Sio f(int x){
if(x=='S')return {-1,-1};
if(x=='I')return {1,0};
if(x=='O')return {0,1};
if(x==0)return {-1,-1};
if(x==1)return {1,0};
if(x==-1)return {0,1};
return {0,0};
}
Sio Add(Sio a,Sio b){
return make_pair(a.first+b.first,a.second+b.second);
}
Sio neg(Sio x){
    return make_pair(-x.first,-x.second);
}

vector <vector <int> > decompo;

vector <int> SubtreeSize;
vector <bool> blocked;
vector <int> parent;
vector <bool> InitBio;
void Init(int node,int prev=-1){
if(InitBio[node])return;
InitBio[node]=true;
SubtreeSize[node]=1;
parent[node]=prev;
for(pair <int,Sio> x:Graph[node]){
    Init(x.first,node);
    if(prev!=x.first)
    SubtreeSize[node]+=SubtreeSize[x.first];
}

}
int root=-1;

int DFS(int node,bool roott=0){
queue<int> q;
q.push(node);
int centroid=node;
int bestSize=SubtreeSize[node];

while(q.size()){
    int curr=q.front();
    q.pop();
    if(blocked[curr])continue;
    int MaxSub=0;
        MaxSub=SubtreeSize[node]-SubtreeSize[curr];


    for(pair <int,Sio> x:Graph[curr]){

    if(!blocked[x.first]&&parent[curr]!=x.first){
        q.push(x.first);
       MaxSub=max(MaxSub,SubtreeSize[x.first]);

    }
    }
    if(MaxSub<bestSize){
        centroid=curr;
        bestSize=MaxSub;
    }

}
    if(roott)root=centroid;
  blocked[centroid]=true;

for(pair <int,Sio> x:Graph[centroid]){
    if(!blocked[x.first])decompo[centroid].push_back(DFS(x.first));
}
  return centroid;

}
vector <Sio> Val;
void SioDist(int node,Sio dist,vector <int>&all,int prev){
    if(blocked[node])return;
    all.push_back(node);
    Val[node]=Add(Val[prev],dist);
    for(pair <int,Sio> x:Graph[node]){
        if(x.first!=prev&&!blocked[x.first])SioDist(x.first,x.second,all,node);
    }


}
#define mod 100000000000031
#define base 300003
long long Hashh(Sio x){
    return ((long long)x.first*base+x.second)%mod;
}
int Resi(){
    queue <pair <int,int> > q;
    q.push({root,-1});
    int rez=0;

    while(q.size()){
        int curr=q.front().first;
        int prev=q.front().second;
        q.pop();
        Val[curr]=make_pair(0,0);
        blocked[curr]=1;
    unordered_map<long long,int> cnt;
        for(pair<int,Sio> x:Graph[curr]){
            if(!blocked[x.first]&&x.first!=prev){
                vector <int> all;

                SioDist(x.first,x.second,all,curr);
                for(int y:all){
                    rez+=cnt[Hashh(neg(Val[y]))];
                    rez+=(Hashh(Val[y])==Hashh(make_pair(0,0)));


                }
                for(int y:all){
                    cnt[Hashh(Val[y])]++;

                }

            }
        }

        for(int x:decompo[curr])q.push({x,curr});

    }
return rez;
}


int main(){
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//freopen("test.in","r",stdin);
//freopen("resenje.txt","w",stdout);
// After function call
auto start = high_resolution_clock::now();
cin >>n;
Graph.resize(n);
parent.resize(n);
InitBio.resize(n);
decompo.resize(n);
blocked.resize(n);
SubtreeSize.resize(n);
Val.resize(n);
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
//cerr << "INIT: "<< duration.count() << endl;

for(int i=0;i<n-1;i++){
    int x,y;
    cin >>x>>y;
    x--;
    y--;
    int s='S';
    cin >>s;
    Graph[x].push_back(make_pair(y,f(s)));
    Graph[y].push_back(make_pair(x,f(s)));


}

Init(0);

DFS(0,1);

for(int i=0;i<n;i++)blocked[i]=0;
// stop = high_resolution_clock::now();
 //duration = duration_cast<microseconds>(stop - start);
//cerr << "DFS: "<< duration.count() << endl;
cout <<Resi()<<endl;

// stop = high_resolution_clock::now();
// duration = duration_cast<microseconds>(stop - start);
//cerr << "TOTAL: "<< duration.count() << endl;
/*
for(int i=0;i<decompo.size();i++){
        cout <<i<<" : ";
for(int j=0;j<decompo[i].size();j++){
    cout <<decompo[i][j]<<" ";
}
cout <<endl;
}*/
}