Given is an undirected connected graph with N vertices numbered 1 to N, and M edges numbered 1 to M.
The given graph may contain multi-edges but not self loops.
Each edge has an integer label between 1 and N (inclusive).
Edge i has a label c_i, and it connects Vertex u_i and v_i bidirectionally.
Snuke will write an integer between 1 and N (inclusive) on each vertex (multiple vertices may have the same integer written on them) and then keep only the edges satisfying the condition below, removing the other edges.
Condition: Let x and y be the integers written on the vertices that are the endpoints of the edge. Exactly one of x and y equals the label of the edge.
We call a way of writing integers on the vertices good if (and only if) the graph is still connected after removing the edges not satisfying the condition above. Determine whether a good way of writing integers exists, and present one such way if it exists.

-----Constraints-----
 - 2 \leq N \leq 10^5
 - N-1 \leq M \leq 2 \times 10^5
 - 1 \leq u_i,v_i,c_i \leq N
 - The given graph is connected and has no self-loops.

-----Input-----
Input is given from Standard Input in the following format:
N M
u_1 v_1 c_1
\vdots
u_M v_M c_M

-----Output-----
If there is no good way of writing integers, print No.
Otherwise, print N lines. The i-th line should contain the integer written on Vertex i.
Any good way of writing integers will be accepted.

-----Sample Input-----
3 4
1 2 1
2 3 2
3 1 3
1 3 1

-----Sample Output-----
1
2
1

 - We write 1, 2, and 1 on Vertex 1, 2, and 3, respectively.
 - Edge 1 connects Vertex 1 and 2, and its label is 1.
 - Only the integer written on Vertex 1 equals the label, so this edge will not get removed.
 - Edge 2 connects Vertex 2 and 3, and its label is 2.
 - Only the integer written on Vertex 2 equals the label, so this edge will not be removed.
 - Edge 3 connects Vertex 1 and 3, and its label is 3.
 - Both integers written on the vertices differ from the label, so this edge will be removed.
 - Edge 4 connects Vertex 1 and 3, and its label is 1.
 - Both integers written on the vertices equal the label, so this edge will be removed.
 - After Edge 3 and 4 are removed, the graph will still be connected, so this is a good way of writing integers.

Difficulty: MEDIUM_HARD

Solutions:
import sys
sys.setrecursionlimit(10 ** 6)

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))
(n, m) = map(int, input().split())
ans = [-1] * n
uf = UnionFind(n)
g = [[] for i in range(n)]
for i in range(m):
	(u, v, c) = map(int, input().split())
	if not uf.same(u - 1, v - 1):
		uf.union(u - 1, v - 1)
		g[u - 1].append((v - 1, c))
		g[v - 1].append((u - 1, c))

def dfs(i):
	for (to, c) in g[i]:
		if ans[to] == -1:
			if ans[i] == c:
				if c == 1:
					ans[to] = c + 1
				else:
					ans[to] = c - 1
			else:
				ans[to] = c
			dfs(to)
ans = [-1] * n
ans[0] = 1
dfs(0)
if -1 in ans:
	print('No')
	return
ans = [a for a in ans]
print(*ans, sep='\n')


import bisect, collections, copy, heapq, itertools, math, string, sys
input = lambda : sys.stdin.readline().rstrip()
sys.setrecursionlimit(10 ** 7)
INF = float('inf')
MOD = 10 ** 9 + 7

def I():
	return int(input())

def F():
	return float(input())

def SS():
	return input()

def LI():
	return [int(x) for x in input().split()]

def LI_():
	return [int(x) - 1 for x in input().split()]

def LF():
	return [float(x) for x in input().split()]

def LSS():
	return input().split()

def resolve():
	(N, M) = LI()
	G = collections.defaultdict(list)
	for _ in range(M):
		(u, v, c) = LI_()
		G[u].append((v, c))
		G[v].append((u, c))
	ans = [-1] * N
	ans[0] = 1

	def dfs(c, p):
		for (n, l) in G[c]:
			if ans[n] == -1:
				if ans[c] == l:
					if l < N - 1:
						ans[n] = l + 1
					else:
						ans[n] = l - 1
				else:
					ans[n] = l
				dfs(n, c)
	dfs(0, -1)
	for i in ans:
		print(i + 1)

def __starting_point():
	resolve()
__starting_point()


from collections import deque

def main():
	(n, m) = map(int, input().split())
	G = dict()
	for i in range(1, n + 1):
		G[i] = dict()
	for i in range(m):
		(u, v, c) = map(int, input().split())
		G[u][v] = c
		G[v][u] = c
	done = [0] * (n + 1)
	done[1] = 1
	dq = deque()
	dq.append(1)
	while dq:
		node = dq.popleft()
		for (dst, dc) in G[node].items():
			if done[dst] == 0:
				if done[node] != dc:
					done[dst] = dc
				elif dc == n:
					done[dst] = 1
				else:
					done[dst] = dc + 1
				dq.append(dst)
	for i in range(1, n + 1):
		print(done[i])
main()


from collections import deque
(n, m) = [int(i) for i in input().split()]
g = [[] for _ in range(n)]
for _ in range(m):
	(u, v, c) = [int(i) - 1 for i in input().split()]
	g[u].append([v, c])
	g[v].append([u, c])
num = [0] * n
d = deque()
d.append(0)
label = [-1] * n
label[0] = 0
while d:
	a = d.pop()
	if num[a]:
		continue
	num[a] = 1
	for (u, c) in g[a]:
		if num[u]:
			continue
		if label[a] != c:
			label[u] = c
		elif c == 0:
			label[u] = 1
		else:
			label[u] = 0
		d.appendleft(u)
print('\n'.join(map(lambda i: str(i + 1), label)))


import numpy as np

def solve(N, G):
	q = np.zeros(N, dtype=np.uint32)
	q[0] = 1
	labels = np.zeros(N + 1, dtype=np.uint32)
	labels[1] = 1
	end = 1
	for head in range(N):
		u = q[head]
		if u < 1:
			break
		for v in list(G[u].keys()):
			if labels[v] > 0:
				continue
			labels[v] = G[u][v] if labels[u] != G[u][v] else labels[u] % N + 1
			q[end] = v
			end += 1
	else:
		return labels[1:]
	return ['No']

def main():
	(N, M) = [int(x) for x in input().split()]
	G = {}
	for i in range(M):
		(u, v, c) = [int(x) for x in input().split()]
		for (u_, v_) in ((u, v), (v, u)):
			if u_ not in G:
				G[u_] = {}
			G[u_][v_] = c
	ans = solve(N, G)
	for i in range(len(ans)):
		print(ans[i])
main()


import sys
sys.setrecursionlimit(10 ** 6)
f = lambda : map(int, input().split())
(n, m) = f()
g = [[] for _ in range(n)]
for _ in range(m):
	(u, v, l) = f()
	g[u - 1] += [(v - 1, l)]
	g[v - 1] += [(u - 1, l)]
a = [0] * n

def dfs(v, p=-1, l=1):
	a[v] = l
	for (c, m) in g[v]:
		if c == p or a[c]:
			continue
		if l == m:
			m = 1 + (m == 1)
		dfs(c, v, m)
dfs(0)
print(*a, sep='\n')


from sys import setrecursionlimit
setrecursionlimit(10 ** 6)
(N, M, *UVC) = map(int, open(0).read().split())
E = [[] for _ in range(N + 1)]
for (u, v, c) in zip(*[iter(UVC)] * 3):
	E[u].append((v, c))
	E[v].append((u, c))
memo = [-1] * (N + 1)
memo[1] = 1

def dfs(cur, par):
	for (nxt, c) in E[cur]:
		if memo[nxt] != -1 or nxt == par:
			continue
		if memo[cur] == c:
			c = 1 + (c == 1)
		memo[nxt] = c
		dfs(nxt, cur)
dfs(1, 0)
for m in memo[1:]:
	print(m)


import sys
sys.setrecursionlimit(10 ** 6)
(n, m) = map(int, input().split())
graph = [[] for _ in range(n)]
for _ in range(m):
	(u, v, c) = map(int, input().split())
	graph[u - 1].append((v - 1, c))
	graph[v - 1].append((u - 1, c))

def dfs(node):
	for (c_node, label) in graph[node]:
		if seen[c_node]:
			continue
		seen[c_node] = True
		if ans[node] == label:
			if label == 1:
				ans[c_node] = 2
			else:
				ans[c_node] = 1
		else:
			ans[c_node] = label
		dfs(c_node)
ans = [None] * n
ans[0] = 1
seen = [False] * n
seen[0] = True
dfs(0)
for i in ans:
	print(i)


import sys
sys.setrecursionlimit(10 ** 7)
input = sys.stdin.readline
f_inf = float('inf')
mod = 10 ** 9 + 7

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def size(self, x):
		return -self.parents[self.find(x)]

	def kruskal(self, edge):
		edge.sort()
		cost_sum = 0
		for (cost, node1, node2) in edge:
			if not self.same(node1, node2):
				cost_sum += cost
				self.union(node1, node2)
		return cost_sum

def resolve():

	def dfs(v):
		for (d, u) in edge[v]:
			if uf.same(v, u):
				continue
			uf.union(u, v)
			if res[v] != d:
				res[u] = d
			else:
				for i in range(1, n + 1):
					if i != d:
						res[u] = i
						break
			dfs(u)
	(n, m) = map(int, input().split())
	edge = [[] for _ in range(n)]
	for _ in range(m):
		(u, v, c) = map(int, input().split())
		edge[u - 1].append([c, v - 1])
		edge[v - 1].append([c, u - 1])
	uf = UnionFind(n)
	res = [0] * n
	res[0] = 1
	dfs(0)
	print(*res, sep='\n')

def __starting_point():
	resolve()
__starting_point()


import sys
from collections import deque
input = sys.stdin.readline
(N, M) = list(map(int, input().split()))
(c, to) = (dict(), [[] for _ in range(N)])

def maxmin(x, y):
	if x < y:
		(x, y) = (y, x)
	return (x, y)
for i in range(M):
	(x, y, z) = list(map(int, input().split()))
	(x, y) = (x - 1, y - 1)
	(x, y) = maxmin(x, y)
	c[x, y] = z
	to[x].append(y)
	to[y].append(x)
d = deque()
d.append(0)
seen = [False] * N
seen[0] = True
mark = [1] * N
while len(d) > 0:
	now = d.popleft()
	for next in to[now]:
		if seen[next]:
			continue
		seen[next] = True
		d.append(next)
		xy = maxmin(next, now)
		if mark[now] == c[xy]:
			mark[next] = mark[now] % N + 1
		else:
			mark[next] = c[xy]
for i in mark:
	print(i)


from sys import stdin, setrecursionlimit
import bisect, collections, copy, heapq, itertools, math, string
setrecursionlimit(10 ** 8)
INF = float('inf')
MOD = 1000000007

def input():
	return stdin.readline().strip()
from collections import defaultdict

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		group_members = collections.defaultdict(list)
		for member in range(self.n):
			group_members[self.find(member)].append(member)
		return group_members

	def __str__(self):
		return '\n'.join((f'{r}: {m}' for (r, m) in self.all_group_members().items()))

def main():
	(n, m) = map(int, input().split())
	uf = UnionFind(n)
	adj = [[] for _ in range(n)]
	for _ in range(m):
		(u, v, c) = map(int, input().split())
		u -= 1
		v -= 1
		if uf.same(u, v):
			continue
		adj[u].append((v, c))
		adj[v].append((u, c))
		uf.union(u, v)
	queue = collections.deque([0])
	ans = [-1] * n
	ans[0] = 1
	while queue:
		now = queue.popleft()
		pnum = ans[now]
		for edge in adj[now]:
			child = edge[0]
			enum = edge[1]
			if ans[child] != -1:
				continue
			queue.append(child)
			if pnum == enum:
				ans[child] = 1 if pnum != 1 else 2
			else:
				ans[child] = enum
	print(*ans, sep='\n')
	return

def __starting_point():
	main()
__starting_point()


import sys
input = sys.stdin.readline

def I():
	return int(input())

def MI():
	return list(map(int, input().split()))

def LI():
	return list(map(int, input().split()))
mod = 10 ** 9 + 7
from collections import defaultdict

class UnionFind:

	def __init__(self, N: int):
		self.N = N
		self.root = [-1] * N
		self.rank = [0] * N

	def __repr__(self):
		return '\n'.join(('{}: {}'.format(r, self.members(r)) for r in self.roots()))

	def find(self, x: int):
		if self.root[x] < 0:
			return x
		else:
			while self.root[x] >= 0:
				x = self.root[x]
			return x

	def union(self, x: int, y: int):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		elif self.rank[x] > self.rank[y]:
			self.root[x] += self.root[y]
			self.root[y] = x
		else:
			self.root[y] += self.root[x]
			self.root[x] = y
			if self.rank[x] == self.rank[y]:
				self.rank[y] += 1

	def same(self, x: int, y: int):
		return self.find(x) == self.find(y)

	def count(self, x):
		return -self.root[self.find(x)]

	def members(self, x):
		_root = self.find(x)
		return [i for i in range(self.N) if self.find == _root]

	def roots(self):
		return [i for (i, x) in enumerate(self.root) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		dd = defaultdict(list)
		for i in range(N):
			root = self.find(i)
			dd[root].append(i)
		return dd

def Kruskal(maxV, edges):
	edges.sort()
	newAdj = [[] for _ in range(N)]
	uf = UnionFind(maxV)
	ans = 0
	for e in edges:
		fro = e[0]
		to = e[1]
		if uf.find(fro) != uf.find(to):
			uf.union(fro, to)
			ans += e[0]
			newAdj[fro].append(to)
			newAdj[to].append(fro)
	return newAdj
(N, M) = MI()
from collections import defaultdict
dd = defaultdict(int)
Edge = []
for _ in range(M):
	(u, v, c) = MI()
	u -= 1
	v -= 1
	c -= 1
	if dd[u, v]:
		continue
	Edge.append((u, v))
	dd[u, v] = c
	dd[v, u] = c
adj = Kruskal(N, Edge)
Col = [-1] * N
import queue
q = queue.Queue()
for v in adj[0]:
	q.put((v, 0))
while not q.empty():
	(v, p) = q.get()
	if Col[p] != dd[v, p]:
		Col[v] = dd[v, p]
	elif Col[p] == 0:
		Col[v] = 1
	else:
		Col[v] = 0
	for nv in adj[v]:
		if nv == 0 or Col[nv] != -1:
			continue
		q.put((nv, v))
col_0 = [0] * N
for v in adj[0]:
	col_0[Col[v]] += 1
for i in range(N):
	if col_0[i] == 0:
		Col[0] = i
		break
for i in range(N):
	print(Col[i] + 1)


from collections import deque
(N, M) = list(map(int, input().split()))
G = [{} for i in range(N)]
for _ in range(M):
	(u, v, c) = list(map(int, input().split()))
	G[u - 1][v - 1] = c - 1
	G[v - 1][u - 1] = c - 1
ans = [-1 for i in range(N)]
ans[0] = 0
q = deque([0])
while q:
	r = q.pop()
	for p in G[r]:
		if ans[p] != -1:
			continue
		if ans[r] == G[p][r]:
			ans[p] = (ans[r] + 1) % N
		else:
			ans[p] = G[p][r]
		q.append(p)
for i in ans:
	print(i + 1)


import sys
input = sys.stdin.readline
from itertools import groupby
from collections import deque
R = lambda : map(int, input().split())
I = lambda : int(input())
S = lambda : input().rstrip('\n')
L = lambda : list(R())

def HalfDead():
	(n, m) = R()
	g = dict()
	for i in range(1, n + 1):
		g[i] = dict()
	for i in range(m):
		(u, v, c) = R()
		g[u][v] = c
		g[v][u] = c
	color = [0] * (n + 2)
	color[1] = 1
	dq = deque()
	dq.append(1)
	while dq:
		frm = dq.popleft()
		for (to, c) in g[frm].items():
			if color[to] == 0:
				if color[frm] != c:
					color[to] = c
				elif c == n:
					color[to] = 1
				else:
					color[to] = c + 1
				dq.append(to)
	for i in range(n):
		print(color[i + 1])
	return

def __starting_point():
	HalfDead()
__starting_point()


import sys
input = sys.stdin.readline
from collections import Counter, deque
(n, m) = map(int, input().split())
E = [list(map(int, input().split())) for i in range(m)]
F = []
(*p,) = range(n)

def root(x):
	if x == p[x]:
		return x
	p[x] = y = root(p[x])
	return y

def unite(x, y):
	px = root(x)
	py = root(y)
	if px == py:
		return 0
	if px < py:
		p[py] = px
	else:
		p[px] = py
	return 1
E.sort()
ans = 0
for (v, w, c) in E:
	if unite(v - 1, w - 1):
		F.append([v, w, c])
		ans += c
g = [[] for i in range(n)]
ans = [0] * n
ans[0] = '?'
used = [False] * (n + 1)
pre = [0] * n
for (u, v, c) in F:
	g[u - 1].append([v - 1, c])
	g[v - 1].append([u - 1, c])
Q = deque()
Q.append(0)
while Q:
	p = Q.popleft()
	for s in g[p]:
		(i, v) = (s[0], s[1])
		if ans[i] == 0:
			if ans[p] == v:
				ans[i] = v + 1
				Q.append(i)
				if ans[i] == n + 1:
					ans[i] = 1
			else:
				ans[i] = v
				Q.append(i)
for (i, v) in g[0]:
	used[v] = True
for i in range(1, n + 1):
	if used[i] == False:
		ans[0] = i
		break
print(*ans, sep='\n')


from collections import defaultdict
from collections import deque

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		group_members = defaultdict(list)
		for member in range(self.n):
			group_members[self.find(member)].append(member)
		return group_members

	def __str__(self):
		return '\n'.join((f'{r}: {m}' for (r, m) in list(self.all_group_members().items())))
(n, m) = list(map(int, input().split()))
V = [[] for i in range(n + 1)]
sets = [set([]) for i in range(n + 1)]
uf = UnionFind(n + 1)
for i in range(m):
	(a, b, c) = list(map(int, input().split()))
	if uf.find(a) != uf.find(b):
		uf.union(a, b)
		V[a].append([b, c])
		V[b].append([a, c])
		sets[a].add(c)
		sets[b].add(c)
p = [-1] * (n + 1)

def out_not_in_number(x):
	ret = -1
	for i in range(1, n + 1):
		if i not in sets[x]:
			ret = i
			break
	return ret
start = 1
p[start] = out_not_in_number(start)
q = deque([])
q.append(start)
while q:
	x = q.popleft()
	for (y, z) in V[x]:
		if p[y] == -1:
			q.append(y)
			if p[x] == z:
				p[y] = out_not_in_number(y)
			else:
				p[y] = z
for i in range(1, n + 1):
	print(p[i])


from collections import defaultdict

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n

	def find(self, x):
		if self.parents[x] < 0:
			return x
		else:
			self.parents[x] = self.find(self.parents[x])
			return self.parents[x]

	def union(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.parents[x] > self.parents[y]:
			(x, y) = (y, x)
		self.parents[x] += self.parents[y]
		self.parents[y] = x

	def size(self, x):
		return -self.parents[self.find(x)]

	def same(self, x, y):
		return self.find(x) == self.find(y)

	def members(self, x):
		root = self.find(x)
		return [i for i in range(self.n) if self.find(i) == root]

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		group_members = defaultdict(list)
		for member in range(self.n):
			group_members[self.find(member)].append(member)
		return group_members

	def __str__(self):
		return '\n'.join((f'{r}: {m}' for (r, m) in list(self.all_group_members().items())))
(n, m) = list(map(int, input().split()))
un = UnionFind(n)
next_edge_dic = {}
flag = False
for _ in range(m):
	(u, v, c) = list(map(int, input().split()))
	u -= 1
	v -= 1
	if not un.same(u, v):
		if u not in next_edge_dic:
			next_edge_dic[u] = []
		next_edge_dic[u].append([v, c])
		if v not in next_edge_dic:
			next_edge_dic[v] = []
		next_edge_dic[v].append([u, c])
		un.union(u, v)
	if un.size(0) == n:
		flag = True
		break
if not flag:
	print('No')
else:
	stack = [0]
	visited = set([0])
	ans = [0] * n
	ans[0] = 1
	while stack:
		edge = stack.pop()
		for (next_edge, label) in next_edge_dic[edge]:
			if next_edge in visited:
				continue
			if ans[edge] == label:
				if label == 1:
					ans[next_edge] = 2
				else:
					ans[next_edge] = 1
			else:
				ans[next_edge] = label
			stack.append(next_edge)
		visited.add(edge)
	for i in range(n):
		print(ans[i])


import sys
sys.setrecursionlimit(10 ** 9)
(N, M) = map(int, input().split())
edges = [[] for _ in range(N)]
for _ in range(M):
	(u, v, c) = map(int, input().split())
	u -= 1
	v -= 1
	edges[u].append((v, c))
	edges[v].append((u, c))
ans = [-1] * N
ans[0] = 1

def dfs(u):
	for (v, c) in edges[u]:
		if ans[v] != -1:
			continue
		if ans[u] == c:
			if c == 1:
				ans[v] = 2
			else:
				ans[v] = 1
		else:
			ans[v] = c
		dfs(v)
dfs(0)
print(*ans, sep='\n')


import sys
from collections import deque
sys.setrecursionlimit(10 ** 7)

def I():
	return int(sys.stdin.readline().rstrip())

def MI():
	return map(int, sys.stdin.readline().rstrip().split())

def LI():
	return list(map(int, sys.stdin.readline().rstrip().split()))

def LI2():
	return list(map(int, sys.stdin.readline().rstrip()))

def S():
	return sys.stdin.readline().rstrip()

def LS():
	return list(sys.stdin.readline().rstrip().split())

def LS2():
	return list(sys.stdin.readline().rstrip())

class UnionFind:

	def __init__(self, n):
		self.par = [i for i in range(n + 1)]
		self.rank = [0] * (n + 1)

	def find(self, x):
		if self.par[x] == x:
			return x
		else:
			self.par[x] = self.find(self.par[x])
			return self.par[x]

	def same_check(self, x, y):
		return self.find(x) == self.find(y)

	def unite(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if self.rank[x] < self.rank[y]:
			(x, y) = (y, x)
		if self.rank[x] == self.rank[y]:
			self.rank[x] += 1
		self.par[y] = x
(N, M) = MI()
Graph = [[] for _ in range(N + 1)]
UF = UnionFind(N)
for _ in range(M):
	(u, v, c) = MI()
	if not UF.same_check(u, v):
		UF.unite(u, v)
		Graph[u].append((v, c))
		Graph[v].append((u, c))
deq = deque([1])
ANS = [-1] * (N + 1)
ANS[1] = 1
while deq:
	i = deq.pop()
	for (j, c) in Graph[i]:
		if ANS[j] != -1:
			continue
		if ANS[i] != c:
			ANS[j] = c
		elif c == 1:
			ANS[j] = 2
		else:
			ANS[j] = 1
		deq.append(j)
print(*ANS[1:], sep='\n')


from sys import stdin
import sys
sys.setrecursionlimit(10 ** 6)
(N, M) = list(map(int, stdin.readline().split()))
g = [[] for i in range(0, N)]
for i in range(0, M):
	(a, b, c) = list(map(int, stdin.readline().split()))
	a -= 1
	b -= 1
	g[a].append((b, c))
	g[b].append((a, c))
vis = [False] * N
col = [-1] * N

def dfs(v):
	nonlocal vis
	nonlocal col
	vis[v] = True
	for (to, c) in g[v]:
		if vis[to] == True:
			continue
		if c == col[v]:
			if c == 1:
				col[to] = 2
			else:
				col[to] = 1
		else:
			col[to] = c
		dfs(to)
col[0] = 1
dfs(0)
for i in range(0, N):
	print(col[i])


import collections
(N, M, *UVC) = [int(_) for _ in open(0).read().split()]
(U, V, C) = [UVC[_::len('UVC')] for _ in range(len('UVC'))]
CUV = []
for (u, v, c) in zip(U, V, C):
	CUV += [(c, u, v)]
CUV.sort()

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * (n + 1)
		self.rank = [0] * (n + 1)

	def find(self, x):
		if self.root[x] < 0:
			return x
		else:
			self.root[x] = self.find(self.root[x])
			return self.root[x]

	def unite(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return 0
		elif self.rank[x] > self.rank[y]:
			self.root[x] += self.root[y]
			self.root[y] = x
		else:
			self.root[y] += self.root[x]
			self.root[x] = y
			if self.rank[x] == self.rank[y]:
				self.rank[y] += 1

	def is_same(self, x, y):
		return self.find(x) == self.find(y)

	def size(self, x):
		return -self.root[self.find(x)]
uf = UnionFind(N)
G = [{} for _ in range(N + 1)]
se = set()
for (c, u, v) in CUV:
	if uf.is_same(u, v):
		continue
	uf.unite(u, v)
	se.add(c)
	G[u][v] = G[v][u] = c
other = (set(range(1, N + 1)) - se).pop()
ans = [-1] * (N + 1)
ans[1] = 1
uf2 = UnionFind(N)
S = [1]
while S:
	u = S.pop()
	for v in G[u]:
		if uf2.is_same(u, v):
			continue
		uf2.unite(u, v)
		c = G[u][v]
		ans[v] = c if c != ans[u] else c % N + 1
		S += [v]
print(*ans[1:], sep='\n')


(N, M) = map(int, input().split())
E = [[] for _ in range(N)]
for _ in range(M):
	(u, v, c) = map(int, input().split())
	u -= 1
	v -= 1
	E[u].append((c, v))
	E[v].append((c, u))
from heapq import heappush, heappop, heapify
used = [0] * N
que = [(c, next, 0) for (c, next) in E[0]]
used[0] = 1
heapify(que)
ans = [-1] * N
ans[0] = 1
while que:
	(cv, v, pre) = heappop(que)
	if used[v]:
		continue
	used[v] = 1
	if cv == ans[pre]:
		ans[v] = N - -(cv + 1) % N
	else:
		ans[v] = cv
	for (cost, next) in E[v]:
		if used[next]:
			continue
		heappush(que, (cost, next, v))
print('\n'.join([str(i) for i in ans]))


import sys
from collections import deque
from heapq import heappush, heappop

def input():
	return sys.stdin.readline().strip()

def main():
	(N, M) = list(map(int, input().split()))
	repn = [[] for _ in range(N + 1)]
	for _ in range(M):
		(u, v, c) = list(map(int, input().split()))
		repn[u].append((c, v))
		repn[v].append((c, u))
	visited = [0] * (N + 1)
	used_edge = [[] for _ in range(N + 1)]
	edge_q = []
	for (c, v) in repn[1]:
		heappush(edge_q, (c, 1, v))
	visited[1] = 1
	while edge_q:
		(c, u, v) = heappop(edge_q)
		if visited[v]:
			continue
		visited[v] = 1
		used_edge[u].append((c, v))
		for (nc, nv) in repn[v]:
			if not visited[nv]:
				heappush(edge_q, (nc, v, nv))
	label = [0] * (N + 1)
	cand = set(range(1, N + 1))
	for (c, v) in used_edge[1]:
		cand.discard(c)
	label[1] = cand.pop()
	q = deque()
	for (c, v) in used_edge[1]:
		q.append((c, 1, v))
	while q:
		(c, u, v) = q.popleft()
		if label[u] == c:
			label[v] = 1 if c != 1 else 2
		else:
			label[v] = c
		for (nc, nv) in used_edge[v]:
			q.append((nc, v, nv))
	for (i, l) in enumerate(label):
		if i == 0:
			continue
		print(l)

def __starting_point():
	main()
__starting_point()


import sys
sys.setrecursionlimit(10 ** 9)
read = lambda : sys.stdin.readline()

def read_ints():
	return list(map(int, read().split()))

def read_intgrid(h):
	return list((list(map(int, read().split())) for i in range(h)))

def read_strgrid(h):
	return list((list(read()) for i in range(h)))

def main():
	(n, m) = map(int, input().split())
	G = [[] for _ in range(n)]
	for i in range(m):
		(a, b, c) = map(int, input().split())
		(a, b) = (a - 1, b - 1)
		G[a].append((b, c))
		G[b].append((a, c))
	vis = [0] * n
	label = [-1] * n
	label[0] = 1

	def dfs(v):
		vis[v] = 1
		for (x, c) in G[v]:
			if vis[x]:
				continue
			if label[x] == -1:
				if label[v] == c:
					if label[v] == 1:
						label[x] = label[v] + 1
					else:
						label[x] = label[v] - 1
				else:
					label[x] = c
			dfs(x)
	dfs(0)
	print('\n'.join(map(str, label)))
	return None

def __starting_point():
	main()
__starting_point()