#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=1e5+5,M=4e5+5;

int edge[M],Next[M],ver[M],head[N];
int tot=0,tmp=0;
int dfn[N],dis[N];
int n,m;

void add(int x,int y,int z){
	ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
}

void dfs(int x){
	dfn[x]=++tmp;
	for(int i=head[x];i;i=Next[i]){
		int y=ver[i];
		if(!dfn[y]){
			if(dis[x]!=edge[i])	dis[y]=edge[i];
			else				dis[y]=dis[x]%n+1;
			dfs(y);
		}
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);add(v,u,w);
	}
	dis[1]=1;
	dfs(1);
	if(tmp<n-1)	puts("No");
	else{
		for(int i=1;i<=n;i++)	printf("%d\n",dis[i]);
	}
} 
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
template <typename T> using vt = vector<T>;
template <typename T> using oset = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
#define pb push_back
#define SZ(x) ((int)((x).size()))
#define EACH(x, a) for (auto& x: a)
#define FOR(i,s,n) for (ll i = (s); (i) < (n); ++i)
#define FORD(i,s,l) for (ll i = (s); (i) >= l; --i)
#define F first
#define S second
#define TC int __tc; cin >> __tc; FOR(case_num,1,__tc+1)
#define TEST(x,i) ((x)&(1ll<<(i)))
#define SET(x,i) ((x)|(1ll<<(i)))
#define FLIP(x,i) ((x)^(1ll<<(i)))
#define CLEAR(x,i) ((x)&~(1ll<<(i)))
const double pi = 4 * atan(1);
using ll = long long;
using pll = pair<ll, ll>;


mt19937 mt_rng(chrono::steady_clock::now().time_since_epoch().count());
ll randint(ll a, ll b) {
	return uniform_int_distribution<ll>(a, b)(mt_rng);
}

template<class T> bool umin(T& a, const T& b) {
	return b<a?a=b, 1:0;
}
template<class T> bool umax(T& a, const T& b) { 
	return a<b?a=b, 1:0;
}

template<class ForwardIterator> void print_vec(ForwardIterator first,
		ForwardIterator last, string sep = " ", string end = "\n") {
	bool ft = true;
	while (first != last) {
		if (!ft) {cout << sep;} else {ft = false;}
		cout << (*first);
		++first;
	}
	cout << end;
}

template<typename T1, typename T2>
std::ostream& operator<<(std::ostream &o, const pair<T1, T2> &p) {
	return o << p.F << " " << p.S;
}

inline ll floorDiv(ll x, ll y) {
	ll d = x / y;
	ll r = x % y;
	return r ? (d - ((x < 0) ^ (y < 0))) : d;
}

ll ceilDiv(ll x, ll y) {
	return -floorDiv(-x, y);
}

ll bin_search(ll lo, ll hi, function<bool(ll)> predicate) {
	int sign = lo < hi ? 1 : -1;
	lo *= sign;
	hi *= sign;
	hi++;
	while (lo < hi) {
		ll mid = lo + floorDiv(hi-lo, 2);
		if (!predicate(sign * mid)) {
			lo = mid + 1;
		} else {
			hi = mid;
		}
	}
	return sign * lo;
}
const ll MOD = 1000000007;
const int MAXN = 100005;

map<int,vector<int>> adj[MAXN];
map<int,map<int,int>> used;
bool visited[MAXN];
int n;

void dfs(int u, vector<int> &ans) {
	visited[u]=true;
	for (auto &p : adj[u]) {
		int val = p.F;
		for (auto v : p.S) {
			if (!visited[v]) {
				ans[v] = (ans[u] == val ? (val+1)%n : val);
				dfs(v, ans);
			} 
		}
	}
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	
	cin >> n;
	int m;
	cin >> m;
	
	vector<int> ans(n,-1);
	
	while(m--) {
		int x, y, v;
		cin >> x >> y >> v; x--; y--; v--;
		adj[x][v].pb(y);
		adj[y][v].pb(x);
	}
	
	ans[0]=0;
	dfs(0,ans);
	
	if (find(ans.begin(),ans.end(),-1) != ans.end()) {
		cout << "No\n";
	} else {
		for (auto v : ans) {
			cout << v+1 << "\n";
		}
	}
	
}
