#include <iostream>
#include <vector>
#define odwiedzone odwiedzony
using namespace std;

void dfs1(int current, int original, vector<int> *na_linii, vector<int> * szefowie, vector<bool>odwiedzone, int n){
	if(current != original){
		na_linii[current].push_back(original);
		na_linii[original].push_back(current);
	}
	odwiedzone[current]=true;
	for(auto it = szefowie[current].begin(); it!=szefowie[current].end(); ++it){
		if(!odwiedzone[*it]) dfs1(*it, original, na_linii, szefowie, odwiedzone, n);
	}

}

int main() {
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	vector<int>szefowie[n];
	vector<int>moze_szefowie[n];
	bool nielubiany[n];
	fill(nielubiany, nielubiany+n, false);
	int stopien_wejscia[n];
	for(int i=0; i<m; ++i){
		int a, b;
		char c;
		cin >> a >> b >> c;
		--a;
		--b;
		if(c=='T'){
			szefowie[a].push_back(b);
		}
		else if(c=='N'){
			moze_szefowie[b].push_back(a);
			nielubiany[b]=true;
		}
		else cout << "ERROR";

	}
	//TUTAJ OGARNIAM NIEsnaski
	bool lider=false;
	for(int i=0; i<n; ++i){
		if(szefowie[i].size()==0 && nielubiany[i]==false){

			lider=true;
			break;
		}
	}
	if(!lider){
		cout << "NIE";
		cerr << 0;
		return 0;
	}
	//1. Upewniam się, że nie ma cyklu; sortuje topologicznie
	fill(stopien_wejscia, stopien_wejscia+n, 0);
	for(int i=0; i<n; ++i){
		for(vector<int>::iterator it = szefowie[i].begin(); it!= szefowie[i].end(); ++it)
			++stopien_wejscia[*it];

	}
	int pozycja =0;
	vector<int>kolejka;
	for(int i=0; i<n; ++i){
		if(stopien_wejscia[i]==0){
			--stopien_wejscia[i];
			kolejka.push_back(i);
			while(!kolejka.empty()){
				int obecny = kolejka.back();
				kolejka.pop_back();
				++pozycja;
				for(vector<int>::iterator it = szefowie[obecny].begin(); it!= szefowie[obecny].end(); ++it){
					--stopien_wejscia[*it];
					if(stopien_wejscia[*it]==0){
						kolejka.push_back(*it);
						--stopien_wejscia[*it];
					}
				}
			}
		}
	}

	if(pozycja!=n){
		cout << "NIE";
		cerr <<1;
		return 0;
	}

	//Muszę znalec wszystkich w linii
	vector<bool> odwiedzone;
	vector<int> na_linii[n];
	odwiedzone.resize(n, false);
	for(int i=0; i<n; ++i){
		fill(odwiedzone.begin(), odwiedzone.end(), false);
		dfs1(i, i, na_linii, szefowie, odwiedzone, n);
	}

	//muszę posortowac NIE i na linii
	bool kubelki[n];
	for(int i=0; i<n; ++i){

		fill(kubelki, kubelki+n, false);
		for(auto it = na_linii[i].begin(); it!=na_linii[i].end(); ++it){
			kubelki[*it] = true;
		}
		for(auto it = moze_szefowie[i].begin(); it!=moze_szefowie[i].end(); ++it){
			if(kubelki[*it])szefowie[i].push_back(*it);
		}

	}

	for(int i=0; i<n; ++i){
		fill(kubelki, kubelki+n, false);
		for(auto it = szefowie[i].begin(); it!=szefowie[i].end(); ++it){
			kubelki[*it] = true;
		}
		szefowie[i].clear();
		for(int j=0; j<n; ++j){
			if(kubelki[j])
				szefowie[i].push_back(j);
		}
	}

	//mam wszystkie potrzebne krawędzie!!!

	//jeszcze raz sortuję topologicznie


	fill(stopien_wejscia, stopien_wejscia+n, 0);
	for(int i=0; i<n; ++i){
		for(vector<int>::iterator it = szefowie[i].begin(); it!= szefowie[i].end(); ++it)
			++stopien_wejscia[*it];

	}
	int posortowane[n];
	pozycja=0;

	//kolejka.clear();
	for(int i=0; i<n; ++i){
		if(stopien_wejscia[i]==0){
			--stopien_wejscia[i];
			kolejka.push_back(i);
			while(!kolejka.empty()){
				int obecny = kolejka.back();
				kolejka.pop_back();
				posortowane[pozycja] = obecny;
				++pozycja;
				for(auto it = szefowie[obecny].begin(); it!= szefowie[obecny].end(); ++it){
					--stopien_wejscia[*it];
					if(stopien_wejscia[*it]==0){
						kolejka.push_back(*it);
						--stopien_wejscia[*it];
					}
				}
			}
		}
	}

	if(pozycja!=n){
		cout << "NIE";
		cerr <<2;
		return 0;
	}


	//zliczam ilosc wychodzacych

	int odpowiedzi[n];
	fill(odpowiedzi, odpowiedzi+n, -2);

	odpowiedzi[posortowane[n-1]] = -1;

	fill(stopien_wejscia, stopien_wejscia+n, 0);
	for(int i=0; i<n; ++i){
		for(vector<int>::iterator it = szefowie[i].begin(); it!= szefowie[i].end(); ++it)
			++stopien_wejscia[*it];
	}




	cout << 0 << "\n";
	for(int i=0; i<n-1; ++i){
		cout << 1 << "\n";
	}


	return 0;
}
