ACL Beginner Contest - Replace Digits

You have a string S of length N. Initially, all characters in S are `1`s.

You will perform queries Q times. In the i-th query, you are given two integers L_i, R_i and a character D_i (which is a digit). Then, you must replace all characters from the L_i-th to the R_i-th (inclusive) with D_i.

After each query, read the string S as a decimal integer, and print its value modulo 998,244,353.

Constraints

* 1 \leq N, Q \leq 200,000
* 1 \leq L_i \leq R_i \leq N
* 1 \leq D_i \leq 9
* All values in input are integers.

Input

Input is given from Standard Input in the following format:


N Q
L_1 R_1 D_1
:
L_Q R_Q D_Q


Output

Print Q lines. In the i-th line print the value of S after the i-th query, modulo 998,244,353.

Examples

Input

8 5
3 6 2
1 4 7
3 8 3
2 2 2
4 5 1


Output

11222211
77772211
77333333
72333333
72311333


Input

200000 1
123 456 7


Output

641437905

Difficulty: UNKNOWN_DIFFICULTY

Starter code:

Solutions:
MOD = 998244353

class LazySegmentTree:
	__slots__ = ['n', 'data', 'lazy', 'me', 'oe', 'fmm', 'fmo', 'foo']

	def __init__(self, monoid_data, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator, func_operator_operator):
		self.me = monoid_identity
		self.oe = operator_identity
		self.fmm = func_monoid_monoid
		self.fmo = func_monoid_operator
		self.foo = func_operator_operator
		self.n = len(monoid_data)
		self.data = monoid_data * 2
		for i in range(self.n - 1, 0, -1):
			self.data[i] = self.fmm(self.data[2 * i], self.data[2 * i + 1])
		self.lazy = [self.oe] * (self.n * 2)

	def replace(self, index, value):
		index += self.n
		for shift in range(index.bit_length() - 1, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		self.data[index] = value
		self.lazy[index] = self.oe
		i = index
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def effect(self, l, r, operator):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) >> 1
		r0 = r // (r & -r) - 1 >> 1
		while r0 > l0:
			indices.append(r0)
			r0 >>= 1
		while l0 > r0:
			indices.append(l0)
			l0 >>= 1
		while l0 and l0 != r0:
			indices.append(r0)
			r0 >>= 1
			if l0 == r0:
				break
			indices.append(l0)
			l0 >>= 1
		while r0:
			indices.append(r0)
			r0 >>= 1
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		while l < r:
			if l & 1:
				self.lazy[l] = self.foo(self.lazy[l], operator)
				l += 1
			if r & 1:
				r -= 1
				self.lazy[r] = self.foo(self.lazy[r], operator)
			l >>= 1
			r >>= 1
		for i in indices:
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def folded(self, l, r):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 >>= 1
		while l0 > r0:
			indices.append(l0)
			l0 >>= 1
		while l0 and l0 != r0:
			indices.append(r0)
			r0 >>= 1
			if l0 == r0:
				break
			indices.append(l0)
			l0 >>= 1
		while r0:
			indices.append(r0)
			r0 >>= 1
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		left_folded = self.me
		right_folded = self.me
		while l < r:
			if l & 1:
				left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
				l += 1
			if r & 1:
				r -= 1
				right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
			l >>= 1
			r >>= 1
		return self.fmm(left_folded, right_folded)

class ModInt:

	def __init__(self, x):
		self.x = x.x if isinstance(x, ModInt) else x % MOD
	__str__ = lambda self: str(self.x)
	__repr__ = __str__
	__int__ = lambda self: self.x
	__index__ = __int__
	__add__ = lambda self, other: ModInt(self.x + ModInt(other).x)
	__sub__ = lambda self, other: ModInt(self.x - ModInt(other).x)
	__mul__ = lambda self, other: ModInt(self.x * ModInt(other).x)
	__pow__ = lambda self, other: ModInt(pow(self.x, ModInt(other).x, MOD))
	__truediv__ = lambda self, other: ModInt(self.x * pow(ModInt(other).x, MOD - 2, MOD))
	__floordiv__ = lambda self, other: ModInt(self.x // ModInt(other).x)
	__radd__ = lambda self, other: ModInt(other + self.x)
	__rsub__ = lambda self, other: ModInt(other - self.x)
	__rpow__ = lambda self, other: ModInt(pow(other, self.x, MOD))
	__rmul__ = lambda self, other: ModInt(other * self.x)
	__rtruediv__ = lambda self, other: ModInt(other * pow(self.x, MOD - 2, MOD))
	__rfloordiv__ = lambda self, other: ModInt(other // self.x)
	__lt__ = lambda self, other: self.x < ModInt(other).x
	__gt__ = lambda self, other: self.x > ModInt(other).x
	__le__ = lambda self, other: self.x <= ModInt(other).x
	__ge__ = lambda self, other: self.x >= ModInt(other).x
	__eq__ = lambda self, other: self.x == ModInt(other).x
	__ne__ = lambda self, other: self.x != ModInt(other).x

def main():
	import sys
	sys.setrecursionlimit(311111)
	ikimasu = sys.stdin.buffer.readline
	ini = lambda : int(ins())
	ina = lambda : list(map(int, ikimasu().split()))
	ins = lambda : ikimasu().strip()
	(n, q) = ina()
	tmp = [(1, 1) for i in range(0, n)]
	tmpx = 1
	tmpx1 = 1
	ten = []
	one = []
	for i in range(311111):
		ten.append(tmpx)
		one.append(tmpx1)
		tmpx1 *= 10
		tmpx1 += 1
		tmpx *= 10
		tmpx1 %= MOD
		tmpx %= MOD

	def op(x1, x2):
		(val1, size1) = x1
		(val2, size2) = x2
		size = size1 + size2
		val = val1 * ten[size2] + val2
		return (val % MOD, size)
	e = (0, 0)

	def maptmp(s, f):
		if f == -1:
			return s
		else:
			return (f * one[s[1] - 1] % MOD, s[1])

	def comp(g, f):
		return f if f != -1 else g
	ident = -1
	tmptree = LazySegmentTree(tmp, e, ident, op, maptmp, comp)
	for _ in range(q):
		(l, r, x) = ina()
		tmptree.effect(l - 1, r, x)
		print(tmptree.folded(0, n)[0])
main()


class LazySegmentTree:

	def __init__(self, n, f, g, h, ef, eh):
		self.n = n
		self.f = f
		self.g = lambda xh, x: g(xh, x) if xh != eh else x
		self.h = h
		self.ef = ef
		self.eh = eh
		l = (self.n - 1).bit_length()
		self.size = 1 << l
		self.tree = [self.ef] * (self.size << 1)
		self.lazy = [self.eh] * ((self.size << 1) + 1)
		self.plt_cnt = 0

	def built(self, array):
		for i in range(self.n):
			self.tree[self.size + i] = array[i]
		for i in range(self.size - 1, 0, -1):
			self.tree[i] = self.f(self.tree[i << 1], self.tree[i << 1 | 1])

	def update(self, i, x):
		i += self.size
		self.propagate_lazy(i)
		self.tree[i] = x
		self.lazy[i] = self.eh
		self.propagate_tree(i)

	def get(self, i):
		i += self.size
		self.propagate_lazy(i)
		return self.g(self.lazy[i], self.tree[i])

	def update_range(self, l, r, x):
		if l >= r:
			return
		l += self.size
		r += self.size
		l0 = l // (l & -l)
		r0 = r // (r & -r)
		self.propagate_lazy(l0)
		self.propagate_lazy(r0 - 1)
		while l < r:
			if r & 1:
				r -= 1
				self.lazy[r] = self.h(x, self.lazy[r])
			if l & 1:
				self.lazy[l] = self.h(x, self.lazy[l])
				l += 1
			l >>= 1
			r >>= 1
		self.propagate_tree(l0)
		self.propagate_tree(r0 - 1)

	def get_range(self, l, r):
		l += self.size
		r += self.size
		self.propagate_lazy(l // (l & -l))
		self.propagate_lazy(r // (r & -r) - 1)
		res_l = self.ef
		res_r = self.ef
		while l < r:
			if l & 1:
				res_l = self.f(res_l, self.g(self.lazy[l], self.tree[l]))
				l += 1
			if r & 1:
				r -= 1
				res_r = self.f(self.g(self.lazy[r], self.tree[r]), res_r)
			l >>= 1
			r >>= 1
		return self.f(res_l, res_r)

	def max_right(self, l, z):
		if l >= self.n:
			return self.n
		l += self.size
		s = self.ef
		while 1:
			while l % 2 == 0:
				l >>= 1
			if not z(self.f(s, self.g(self.lazy[l], self.tree[l]))):
				while l < self.size:
					l *= 2
					if z(self.f(s, self.g(self.lazy[l], self.tree[l]))):
						s = self.f(s, self.g(self.lazy[l], self.tree[l]))
						l += 1
				return l - self.size
			s = self.f(s, self.g(self.lazy[l], self.tree[l]))
			l += 1
			if l & -l == l:
				break
		return self.n

	def min_left(self, r, z):
		if r <= 0:
			return 0
		r += self.size
		s = self.ef
		while 1:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not z(self.f(self.g(self.lazy[r], self.tree[r]), s)):
				while r < self.size:
					r = r * 2 + 1
					if z(self.f(self.g(self.lazy[r], self.tree[r]), s)):
						s = self.f(self.g(self.lazy[r], self.tree[r]), s)
						r -= 1
				return r + 1 - self.size
			s = self.f(self.g(self.lazy[r], self.tree[r]), s)
			if r & -r == r:
				break
		return 0

	def propagate_lazy(self, i):
		for k in range(i.bit_length() - 1, 0, -1):
			x = i >> k
			if self.lazy[x] == self.eh:
				continue
			laz = self.lazy[x]
			self.lazy[x << 1 | 1] = self.h(laz, self.lazy[x << 1 | 1])
			self.lazy[x << 1] = self.h(laz, self.lazy[x << 1])
			self.tree[x] = self.g(laz, self.tree[x])
			self.lazy[x] = self.eh

	def propagate_tree(self, i):
		while i > 1:
			i >>= 1
			self.tree[i] = self.f(self.g(self.lazy[i << 1], self.tree[i << 1]), self.g(self.lazy[i << 1 | 1], self.tree[i << 1 | 1]))

	def __getitem__(self, i):
		return self.get(i)

	def __iter__(self):
		for x in range(1, self.size):
			if self.lazy[x] == self.eh:
				continue
			self.lazy[x << 1 | 1] = self.h(self.lazy[x], self.lazy[x << 1 | 1])
			self.lazy[x << 1] = self.h(self.lazy[x], self.lazy[x << 1])
			self.tree[x] = self.g(self.lazy[x], self.tree[x])
			self.lazy[x] = self.eh
		for (xh, x) in zip(self.lazy[self.size:self.size + self.n], self.tree[self.size:self.size + self.n]):
			yield self.g(xh, x)

	def __str__(self):
		return str(list(self))
from itertools import accumulate
import sys
input = sys.stdin.readline
MOD = 998244353
off = 10 ** 7
(N, Q) = map(int, input().split())
P = [pow(10, p, MOD) for p in range(N + 1)]
SP = [0]
for p in P:
	SP.append((SP[-1] + p) % MOD)
ef = 0

def f(x, y):
	(x0, x1) = divmod(x, off)
	(y0, y1) = divmod(y, off)
	res = x0 * P[y1] + y0
	res %= MOD
	return res * off + x1 + y1
eh = -1

def h(a, b):
	return a if a != eh else b

def g(a, x):
	x1 = x % off
	res = a * SP[x1] % MOD
	return res * off + x1
st = LazySegmentTree(N, f, g, h, ef, eh)
st.built([off + 1] * N)
res = [''] * Q
for i in range(Q):
	(L, R, D) = map(int, input().split())
	st.update_range(L - 1, R, D)
	res[i] = str(st.get_range(0, N) // off % MOD)
print('\n'.join(res))


import sys

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

class LazySegmentTree:

	def __init__(self, init, unitX, unitA, f, g, h):
		self.f = f
		self.g = g
		self.h = h
		self.unitX = unitX
		self.unitA = unitA
		self.f = f
		if type(init) == int:
			self.n = init
			self.X = [unitX] * (self.n * 2)
			self.size = [1] * (self.n * 2)
		else:
			self.n = len(init)
			self.X = [unitX] * self.n + init + [unitX] * (self.n - len(init))
			self.size = [0] * self.n + [1] * len(init) + [0] * (self.n - len(init))
			for i in range(self.n - 1, 0, -1):
				self.X[i] = self.f(self.X[i * 2], self.X[i * 2 | 1])
		for i in range(self.n - 1, 0, -1):
			self.size[i] = self.size[i * 2] + self.size[i * 2 | 1]
		self.A = [unitA] * (self.n * 2)

	def update(self, i, x):
		i += self.n
		self.X[i] = x
		i >>= 1
		while i:
			self.X[i] = self.f(self.X[i * 2], self.X[i * 2 | 1])
			i >>= 1

	def calc(self, i):
		return self.g(self.X[i], self.A[i], self.size[i])

	def calc_above(self, i):
		i >>= 1
		while i:
			self.X[i] = self.f(self.calc(i * 2), self.calc(i * 2 | 1))
			i >>= 1

	def propagate(self, i):
		self.X[i] = self.g(self.X[i], self.A[i], self.size[i])
		self.A[i * 2] = self.h(self.A[i * 2], self.A[i])
		self.A[i * 2 | 1] = self.h(self.A[i * 2 | 1], self.A[i])
		self.A[i] = self.unitA

	def propagate_above(self, i):
		H = i.bit_length()
		for h in range(H, 0, -1):
			self.propagate(i >> h)

	def propagate_all(self):
		for i in range(1, self.n):
			self.propagate(i)

	def getrange(self, l, r):
		l += self.n
		r += self.n
		(l0, r0) = (l // (l & -l), r // (r & -r) - 1)
		self.propagate_above(l0)
		self.propagate_above(r0)
		al = self.unitX
		ar = self.unitX
		while l < r:
			if l & 1:
				al = self.f(al, self.calc(l))
				l += 1
			if r & 1:
				r -= 1
				ar = self.f(self.calc(r), ar)
			l >>= 1
			r >>= 1
		return self.f(al, ar)

	def getvalue(self, i):
		i += self.n
		self.propagate_above(i)
		return self.calc(i)

	def operate_range(self, l, r, a):
		l += self.n
		r += self.n
		(l0, r0) = (l // (l & -l), r // (r & -r) - 1)
		self.propagate_above(l0)
		self.propagate_above(r0)
		while l < r:
			if l & 1:
				self.A[l] = self.h(self.A[l], a)
				l += 1
			if r & 1:
				r -= 1
				self.A[r] = self.h(self.A[r], a)
			l >>= 1
			r >>= 1
		self.calc_above(l0)
		self.calc_above(r0)

	def max_right(self, l, z):
		if l >= self.n:
			return self.n
		l += self.n
		s = self.unitX
		while 1:
			while l % 2 == 0:
				l >>= 1
			if not z(self.f(s, self.calc(l))):
				while l < self.n:
					l *= 2
					if z(self.f(s, self.calc(l))):
						s = self.f(s, self.calc(l))
						l += 1
				return l - self.n
			s = self.f(s, self.calc(l))
			l += 1
			if l & -l == l:
				break
		return self.n

	def min_left(self, r, z):
		if r <= 0:
			return 0
		r += self.n
		s = self.unitX
		while 1:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not z(self.f(self.calc(r), s)):
				while r < self.n:
					r = r * 2 + 1
					if z(self.f(self.calc(r), s)):
						s = self.f(self.calc(r), s)
						r -= 1
				return r + 1 - self.n
			s = self.f(self.calc(r), s)
			if r & -r == r:
				break
		return 0

def main():
	P = 998244353

	def f(x, y):
		return ((x[0] + y[0]) % P, x[1] + y[1])

	def g(x, a, s):
		return (x[1] * a % P, x[1]) if a != 10 ** 10 else x

	def h(a, b):
		return b if b != 10 ** 10 else a
	unitX = (0, 0)
	unitA = 10 ** 10
	(N, Q) = map(int, input().split())
	A = [(1, 1)]
	for _ in range(N - 1):
		now = A[-1][0]
		A.append((now * 10 % P, now * 10 % P))
	st = LazySegmentTree(A[::-1], unitX, unitA, f, g, h)
	for _ in range(Q):
		(l, r, d) = map(int, input().split())
		st.operate_range(l - 1, r, d)
		print(st.getrange(0, N)[0])
main()


import sys
input = sys.stdin.buffer.readline
mod = 998244353
max_n = 262144 + 10
pow_list = [1] * max_n
cum_pow = [0] * max_n
cum_pow[0] = 1
for i in range(1, max_n):
	pow_list[i] = pow_list[i - 1] * 10
	pow_list[i] %= mod
	cum_pow[i] += cum_pow[i - 1] + pow_list[i]
	cum_pow[i] %= mod
cum_pow = [0] + cum_pow

class LazySegmentTree:

	def __init__(self, n, ele, lazy_ele, mod=mod):
		self.n = n
		self.ele = ele
		self.lazy_ele = lazy_ele
		self.num = 2 ** (self.n - 1).bit_length()
		self.SEG = [self.ele] * (2 * self.num)
		self.LAZY = [self.lazy_ele] * (2 * self.num)
		self.node = [1] * (self.num + self.n) + [0] * (self.num - self.n)
		for i in reversed(range(1, self.num)):
			self.node[i] = self.node[2 * i] + self.node[2 * i + 1]

	def func(self, a, b, b_node):
		if b == 0:
			return a
		if a == 0:
			return b
		return (a * pow_list[b_node] + b) % mod

	def calc(self, idx):
		if self.LAZY[idx] == -1:
			return self.SEG[idx]
		node_num = self.node[idx]
		res = self.LAZY[idx] * cum_pow[node_num] % mod
		return res

	def lazy_func(self, a, b):
		return b

	def initialize(self, A):
		for (i, val) in enumerate(A):
			i += self.num
			self.SEG[i] = val
		for i in reversed(range(1, self.num)):
			self.SEG[i] = self.func(self.SEG[2 * i], self.SEG[2 * i + 1], self.node[2 * i + 1])

	def propagate_point(self, idx):
		if self.LAZY[idx] >= 0:
			self.SEG[idx] = self.calc(idx)
			self.LAZY[2 * idx] = self.lazy_func(self.LAZY[2 * idx], self.LAZY[idx])
			self.LAZY[2 * idx + 1] = self.lazy_func(self.LAZY[2 * idx + 1], self.LAZY[idx])
			self.LAZY[idx] = lazy_ele

	def propagate_above(self, idx):
		height = idx.bit_length() - 1
		for h in reversed(range(1, height + 1)):
			self.propagate_point(idx >> h)

	def recalc_above(self, idx):
		while idx > 1:
			idx //= 2
			self.SEG[idx] = self.func(self.calc(2 * idx), self.calc(2 * idx + 1), self.node[2 * idx + 1])

	def update_point(self, idx):
		idx += self.num
		while idx > 0:
			idx //= 2
			self.SEG[idx] = self.func(self.calc(self.SEG[2 * idx]), self.calc(self.SEG[2 * idx + 1]), self.node[2 * idx + 1])

	def update_range(self, left, right, mono):
		left += self.num
		right += self.num
		left_temp = left // (left & -left)
		right_temp = right // (right & -right) - 1
		self.propagate_above(left_temp)
		self.propagate_above(right_temp)
		while left < right:
			if left & 1:
				self.LAZY[left] = self.lazy_func(self.LAZY[left], mono)
				left += 1
			if right & 1:
				right -= 1
				self.LAZY[right] = self.lazy_func(self.LAZY[right], mono)
			left //= 2
			right //= 2
		self.recalc_above(left_temp)
		self.recalc_above(right_temp)

	def get_range(self, left, right):
		left += self.num
		right += self.num
		self.propagate_above(left // (left & -left))
		self.propagate_above(right // (right & -right) - 1)
		res_left = self.ele
		res_left_node = 0
		res_right = self.ele
		res_right_node = 0
		while left < right:
			if left & 1:
				res_left = self.func(res_left, self.calc(left), res_left_node)
				res_left_node += self.node[left]
				left += 1
			if right & 1:
				right -= 1
				res_right = self.func(self.calc(right), res_right, res_right_node)
				res_right_node += self.node[right]
			left //= 2
			right //= 2
		return self.func(res_right, res_left, res_left_node) % mod
ele = 0
lazy_ele = -1
(n, q) = map(int, input().split())
A = [1 for _ in range(n)]
LST = LazySegmentTree(n, ele, lazy_ele)
LST.initialize(A)
for _ in range(q):
	(l, r, d) = map(int, input().split())
	l -= 1
	LST.update_range(l, r, d)
	print(LST.get_range(0, n) % mod)


class LazySegTree:

	def __init__(self, op, e, mapping, composition, id, n: int=-1, v: list=[]):
		assert (len(v) > 0) | (n > 0)
		if len(v) == 0:
			v = [e()] * n
		self.__n = len(v)
		self.__log = (self.__n - 1).bit_length()
		self.__size = 1 << self.__log
		self.__d = [e()] * (2 * self.__size)
		self.__lz = [id()] * self.__size
		self.__op = op
		self.__e = e
		self.__mapping = mapping
		self.__composition = composition
		self.__id = id
		for i in range(self.__n):
			self.__d[self.__size + i] = v[i]
		for i in range(self.__size - 1, 0, -1):
			self.__update(i)

	def __update(self, k: int):
		self.__d[k] = self.__op(self.__d[2 * k], self.__d[2 * k + 1])

	def __all_apply(self, k: int, f):
		self.__d[k] = self.__mapping(f, self.__d[k])
		if k < self.__size:
			self.__lz[k] = self.__composition(f, self.__lz[k])

	def __push(self, k: int):
		self.__all_apply(2 * k, self.__lz[k])
		self.__all_apply(2 * k + 1, self.__lz[k])
		self.__lz[k] = self.__id()

	def set(self, p: int, x):
		assert (0 <= p) & (p < self.__n)
		p += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(p >> i)
		self.__d[p] = x
		for i in range(1, self.__log + 1):
			self.__update(p >> i)

	def get(self, p: int):
		assert (0 <= p) & (p < self.__n)
		p += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(p >> i)
		return self.__d[p]

	def prod(self, l: int, r: int):
		assert (0 <= l) & (l <= r) & (r <= self.__n)
		if l == r:
			return self.__e()
		l += self.__size
		r += self.__size
		for i in range(self.__log, 0, -1):
			if l >> i << i != l:
				self.__push(l >> i)
			if r >> i << i != r:
				self.__push(r >> i)
		sml = self.__e()
		smr = self.__e()
		while l < r:
			if l & 1:
				sml = self.__op(sml, self.__d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.__op(self.__d[r], smr)
			l //= 2
			r //= 2
		return self.__op(sml, smr)

	def all_prod(self):
		return self.__d[1]

	def apply(self, p: int, f):
		assert (0 <= p) & (p < self.__n)
		p += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(p >> i)
		self.__d[p] = self.__mapping(f, self.__d[p])
		for i in range(1, self.__log + 1):
			self.__update(p >> i)

	def apply_lr(self, l: int, r: int, f):
		assert (0 <= l) & (l <= r) & (r <= self.__n)
		if l == r:
			return
		l += self.__size
		r += self.__size
		for i in range(self.__log, 0, -1):
			if l >> i << i != l:
				self.__push(l >> i)
			if r >> i << i != r:
				self.__push(r - 1 >> i)
		(l2, r2) = (l, r)
		while l < r:
			if l & 1:
				self.__all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.__all_apply(r, f)
			l //= 2
			r //= 2
		(l, r) = (l2, r2)
		for i in range(1, self.__log + 1):
			if l >> i << i != l:
				self.__update(l >> i)
			if r >> i << i != r:
				self.__update(r - 1 >> i)

	def max_right(self, l: int, g):
		assert (0 <= l) & (l <= self.__n)
		assert g(self.__e())
		if l == self.__n:
			return self.__n
		l += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(l >> i)
		sm = self.__e()
		while True:
			while l % 2 == 0:
				l //= 2
			if not g(self.__op(sm, self.__d[l])):
				while l < self.__size:
					self.__push(l)
					l *= 2
					if g(self.__op(sm, self.__d[l])):
						sm = self.__op(sm, self.__d[l])
						l += 1
				return l - self.__size
			sm = self.__op(sm, self.__d[l])
			l += 1
			if l & -l == l:
				break
		return self.__n

	def min_left(self, r: int, g):
		assert (0 <= r) & (r <= self.__n)
		assert g(self.__e())
		if r == 0:
			return 0
		r += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(r - 1 >> i)
		sm = self.__e()
		while True:
			r -= 1
			while (r > 1) & r % 2:
				r //= 2
			if not g(self.__op(self.__d[r], sm)):
				while r < self.__size:
					self.__push(r)
					r = 2 * r + 1
					if g(self.__op(self.__d[r], sm)):
						sm = self.__op(self.__d[r], sm)
						r -= 1
				return r + 1 - self.__size
			sm = self.__op(self.__d[r], sm)
			if r & -r == r:
				break
		return 0

	def all_push(self):
		for i in range(1, self.__size):
			self.__push(i)

	def get_all(self):
		self.all_push()
		return self.__d[self.__size:self.__size + self.__n]

	def print(self):
		print(list(map(lambda x: divmod(x, 1 << 30), self.__d)))
		print(self.__lz)
		print('------------------')
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
(n, q, *query) = map(int, read().split())
MOD = 998244353
mod_10 = [1] * (n + 1)
mod_11 = [0] * (n + 1)
for i in range(1, n + 1):
	mod_10[i] = mod_10[i - 1] * 10 % MOD
	mod_11[i] = (mod_11[i - 1] * 10 + 1) % MOD

def op(x, y):
	(x0, x1) = divmod(x, 1 << 30)
	(y0, y1) = divmod(y, 1 << 30)
	if x == 0:
		return y
	if y == 0:
		return x
	res0 = x0 + y0
	res1 = (x1 * mod_10[y0] + y1) % MOD
	return (res0 << 30) + res1

def mapping(f, x):
	if f == -1:
		return x
	(x0, x1) = divmod(x, 1 << 30)
	res1 = mod_11[x0] * f % MOD
	return (x0 << 30) + res1

def composition(f, g):
	if f == -1:
		return g
	return f
v = [(1 << 30) + 1] * n
lst = LazySegTree(op=op, e=lambda : 0, mapping=mapping, composition=composition, id=lambda : -1, v=v)
ans = []
it = iter(query)
for (l, r, d) in zip(it, it, it):
	lst.apply_lr(l - 1, r, d)
	tmp = lst.all_prod()
	ans.append(tmp % (1 << 30))
print('\n'.join(map(str, ans)))


class LazySegmentTree:
	__slots__ = ['n', 'data', 'lazy', 'me', 'oe', 'fmm', 'fmo', 'foo']

	def __init__(self, monoid_data, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator, func_operator_operator):
		self.me = monoid_identity
		self.oe = operator_identity
		self.fmm = func_monoid_monoid
		self.fmo = func_monoid_operator
		self.foo = func_operator_operator
		self.n = len(monoid_data)
		self.data = monoid_data * 2
		for i in range(self.n - 1, 0, -1):
			self.data[i] = self.fmm(self.data[2 * i], self.data[2 * i + 1])
		self.lazy = [self.oe] * (self.n * 2)

	def replace(self, index, value):
		index += self.n
		for shift in range(index.bit_length() - 1, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		self.data[index] = value
		self.lazy[index] = self.oe
		i = index
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def effect(self, l, r, operator):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) >> 1
		r0 = r // (r & -r) - 1 >> 1
		while r0 > l0:
			indices.append(r0)
			r0 >>= 1
		while l0 > r0:
			indices.append(l0)
			l0 >>= 1
		while l0 and l0 != r0:
			indices.append(r0)
			r0 >>= 1
			if l0 == r0:
				break
			indices.append(l0)
			l0 >>= 1
		while r0:
			indices.append(r0)
			r0 >>= 1
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		while l < r:
			if l & 1:
				self.lazy[l] = self.foo(self.lazy[l], operator)
				l += 1
			if r & 1:
				r -= 1
				self.lazy[r] = self.foo(self.lazy[r], operator)
			l >>= 1
			r >>= 1
		for i in indices:
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def folded(self, l, r):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 >>= 1
		while l0 > r0:
			indices.append(l0)
			l0 >>= 1
		while l0 and l0 != r0:
			indices.append(r0)
			r0 >>= 1
			if l0 == r0:
				break
			indices.append(l0)
			l0 >>= 1
		while r0:
			indices.append(r0)
			r0 >>= 1
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		left_folded = self.me
		right_folded = self.me
		while l < r:
			if l & 1:
				left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
				l += 1
			if r & 1:
				r -= 1
				right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
			l >>= 1
			r >>= 1
		return self.fmm(left_folded, right_folded)
import sys
mod = 998244353
p = 1
n = 0
p10 = []
n11 = []
for i in range(202020):
	p10.append(p)
	n11.append(n)
	p = p * 10 % mod
	n = (n * 10 + 1) % mod

def op(a, b):
	(a_val, a_siz) = a
	(b_val, b_siz) = b
	siz = a_siz + b_siz
	val = a_val * p10[b_siz] + b_val
	return (val % mod, siz)
e = (0, 0)

def mapping(a, f):
	if f == 0:
		return a
	siz = a[1]
	return (f * n11[siz] % mod, siz)
aaa = lambda g, f: f if f != 0 else g
i = 0
(N, Q) = map(int, sys.stdin.buffer.readline().split())
seg = LazySegmentTree([(1, 1) for _ in range(N)], e, i, op, mapping, aaa)
LRD = [list(map(int, input().split())) for _ in range(Q)]
Ans = []
for (l, r, d) in LRD:
	seg.effect(l - 1, r, d)
	ans = seg.folded(0, N)[0]
	Ans.append(ans)
print('\n'.join(map(str, Ans)))


import sys
readline = sys.stdin.buffer.readline
INF = 1 << 60

def read_int():
	return int(readline())

def read_int_n():
	return list(map(int, readline().split()))

def read_float():
	return float(readline())

def read_float_n():
	return list(map(float, readline().split()))

def read_str():
	return readline().strip()

def read_str_n():
	return readline().strip().split()

def ep(*args):
	print(*args, file=sys.stderr)

def mt(f):
	import time

	def wrap(*args, **kwargs):
		s = time.perf_counter()
		ret = f(*args, **kwargs)
		e = time.perf_counter()
		ep(e - s, 'sec')
		return ret
	return wrap

class LazySegmentTree:

	def __init__(self, op, e, mapping, composition, im, init_array):
		self.op = op
		self.e = e
		self.mapping = mapping
		self.composition = composition
		self.im = im
		l = len(init_array)

		def ceil_pow2(n):
			x = 0
			while 1 << x < n:
				x += 1
			return x
		self.log = ceil_pow2(l)
		self.size = 1 << self.log
		self.d = [e() for _ in range(2 * self.size)]
		self.lz = [im() for _ in range(self.size)]
		for (i, a) in enumerate(init_array):
			self.d[i + self.size] = a
		for i in range(self.size - 1, 0, -1):
			self.__update(i)

	def set(self, p, x):
		p += self.size
		for i in range(self.log, 0, -1):
			self.__push(p >> i)
		self.d[p] = x
		for i in range(1, self.log + 1):
			self.__update(p >> i)

	def __getitem__(self, p):
		p += self.size
		for i in range(self.log, 0, -1):
			self.__push(p >> i)
		return self.d[p]

	def prod(self, l, r):
		if l == r:
			return self.e()
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.__push(l >> i)
			if r >> i << i != r:
				self.__push(r >> i)
		sml = self.e()
		smr = self.e()
		while l < r:
			if l & 1:
				sml = self.op(sml, self.d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.d[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def apply(self, l, r, f):
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.__push(l >> i)
			if r >> i << i != r:
				self.__push(r - 1 >> i)
		(l2, r2) = (l, r)
		while l < r:
			if l & 1:
				self.__all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.__all_apply(r, f)
			l >>= 1
			r >>= 1
		(l, r) = (l2, r2)
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.__update(l >> i)
			if r >> i << i != r:
				self.__update(r - 1 >> i)

	def __update(self, k):
		self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])

	def __all_apply(self, k, f):
		self.d[k] = self.mapping(f, self.d[k])
		if k < self.size:
			self.lz[k] = self.composition(f, self.lz[k])

	def __push(self, k):
		self.__all_apply(2 * k, self.lz[k])
		self.__all_apply(2 * k + 1, self.lz[k])
		self.lz[k] = self.im()
M = 998244353
m = 1 << 32
m -= 1

def ser(a, b):
	return (a << 32) + b

def des(v):
	return (v >> 32, v & m)

def e():
	return 0

def op(sl, sr):
	sl = des(sl)
	sr = des(sr)
	return ser((sl[0] + sr[0]) % M, (sl[1] + sr[1]) % M)

def mapping(fl, sr):
	if fl == 0:
		return sr
	sr = des(sr)
	return ser(sr[1] * fl % M, sr[1])

def composition(fl, fr):
	if fl == 0:
		return fr
	return fl

def im():
	return 0

@mt
def slv(N, Q, LRQ):
	A = []
	for i in range(N):
		v = pow(10, N - i - 1, M)
		v %= M
		A.append(ser(v, v))
	st = LazySegmentTree(op, e, mapping, composition, im, A)
	ans = []
	for (i, (l, r, q)) in enumerate(LRQ, start=1):
		l -= 1
		st.apply(l, r, q)
		ans.append(des(st.prod(0, N))[0])
	return ans

def main():
	(N, Q) = read_int_n()
	LRQ = [read_int_n() for _ in range(Q)]
	print(*slv(N, Q, LRQ), sep='\n')
main()


class LazySegmentTree:

	def __init__(self, n, op, e, mapping, composition, id):
		self.n = n
		self.op = op
		self.e = e
		self.mapping = mapping
		self.composition = composition
		self.id = id
		self.log = (n - 1).bit_length()
		self.size = 1 << self.log
		self.data = [e] * (2 * self.size)
		self.lazy = [id] * self.size

	def update(self, k):
		self.data[k] = self.op(self.data[2 * k], self.data[2 * k + 1])

	def all_apply(self, k, f):
		self.data[k] = self.mapping(f, self.data[k])
		if k < self.size:
			self.lazy[k] = self.composition(f, self.lazy[k])

	def push(self, k):
		self.all_apply(2 * k, self.lazy[k])
		self.all_apply(2 * k + 1, self.lazy[k])
		self.lazy[k] = self.id

	def build(self, arr):
		for (i, a) in enumerate(arr):
			self.data[self.size + i] = a
		for i in range(self.size - 1, 0, -1):
			self.update(i)

	def set(self, p, x):
		p += self.size
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		self.data[p] = x
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def get(self, p):
		p += self.size
		for i in range(1, self.log + 1):
			self.push(p >> i)
		return self.data[p]

	def prod(self, l, r):
		if l == r:
			return self.e
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r >> i)
		sml = smr = self.e
		while l < r:
			if l & 1:
				sml = self.op(sml, self.data[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.data[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def all_prod(self):
		return self.data[1]

	def apply(self, p, f):
		p += self.size
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		self.data[p] = self.mapping(f, self.data[p])
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def range_apply(self, l, r, f):
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r - 1 >> i)
		l2 = l
		r2 = r
		while l < r:
			if l & 1:
				self.all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.all_apply(r, f)
			l >>= 1
			r >>= 1
		l = l2
		r = r2
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.update(l >> i)
			if r >> i << i != r:
				self.update(r - 1 >> i)

	def max_right(self, l, g):
		if l == self.n:
			return self.n
		l += self.size
		for i in range(self.log, 0, -1):
			self.push(l >> i)
		sm = self.e
		while True:
			while l % 2 == 0:
				l >>= 1
			if not g(self.op(sm, self.data[l])):
				while l < self.size:
					self.push(l)
					l = 2 * l
					if g(self.op(sm, self.data[l])):
						sm = self.op(sm, self.data[l])
						l += 1
				return l - self.size
			sm = self.op(sm, self.data[l])
			l += 1
			if l & -l == l:
				return self.n

	def min_left(self, r, g):
		if r == 0:
			return 0
		r += self.size
		for i in range(self.log, 0, -1):
			self.push(r - 1 >> i)
		sm = self.e
		while True:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(self.op(self.data[r], sm)):
				while r < self.size:
					self.push(r)
					r = 2 * r + 1
					if g(self.op(self.data[r], sm)):
						sm = self.op(self.data[r], sm)
						r -= 1
				return r + 1 - self.size
			sm = self.op(self.data[r], sm)
			if r & -r == r:
				return 0
import sys
input = sys.stdin.readline
INF = pow(10, 18)
mod = 998244353
po32 = pow(2, 32)
(n, q) = map(int, input().split())
lrd = [list(map(int, input().split())) for _ in range(q)]

def op(x, y):
	(xv, xw) = x
	(yv, yw) = y
	return ((xv + yv) % mod, (xw + yw) % mod)

def mapping(p, x):
	if p == INF:
		return x
	(xv, xw) = x
	return (xw * p % mod, xw)

def composition(p, q):
	if p != INF:
		return p
	return q
e = (0, 0)
id = INF
ary = [(pow(10, n - i - 1, mod), pow(10, n - i - 1, mod)) for i in range(n)]
lst = LazySegmentTree(n, op, e, mapping, composition, id)
lst.build(ary)
ans = []
for (l, r, d) in lrd:
	lst.range_apply(l - 1, r, d)
	v = lst.all_prod()
	ans.append(v[0] % mod)
print(*ans, sep='\n')


import sys
input = sys.stdin.readline

class LazySegmentTree:

	def __init__(self, n, op, e, mapping, composition, id):
		self.n = n
		self.op = op
		self.e = e
		self.mapping = mapping
		self.composition = composition
		self.id = id
		self.log = (n - 1).bit_length()
		self.size = 1 << self.log
		self.d = [e] * (2 * self.size)
		self.lz = [id] * self.size

	def update(self, k):
		self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])

	def all_apply(self, k, f):
		self.d[k] = self.mapping(f, self.d[k])
		if k < self.size:
			self.lz[k] = self.composition(f, self.lz[k])

	def push(self, k):
		self.all_apply(2 * k, self.lz[k])
		self.all_apply(2 * k + 1, self.lz[k])
		self.lz[k] = self.id

	def build(self, arr):
		for (i, a) in enumerate(arr):
			self.d[self.size + i] = a
		for i in range(1, self.size)[::-1]:
			self.update(i)

	def set(self, p, x):
		p += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(p >> i)
		self.d[p] = x
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def get(self, p):
		p += self.size
		for i in range(1, self.log + 1):
			self.push(p >> i)
		return self.d[p]

	def prod(self, l, r):
		if l == r:
			return self.e
		l += self.size
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r >> i)
		sml = smr = self.e
		while l < r:
			if l & 1:
				sml = self.op(sml, self.d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.d[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def all_prod(self):
		return self.d[1]

	def apply(self, p, f):
		p += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(p >> i)
		self.d[p] = self.mapping(f, self.d[p])
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def range_apply(self, l, r, f):
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r - 1 >> i)
		l2 = l
		r2 = r
		while l < r:
			if l & 1:
				self.all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.all_apply(r, f)
			l >>= 1
			r >>= 1
		l = l2
		r = r2
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.update(l >> i)
			if r >> i << i != r:
				self.update(r - 1 >> i)

	def max_right(self, l, g):
		if l == self.n:
			return self.n
		l += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(l >> i)
		sm = self.e
		while True:
			while l % 2 == 0:
				l >>= 1
			if not g(self.op(sm, self.d[l])):
				while l < self.size:
					self.push(l)
					l = 2 * l
					if g(self.op(sm, self.d[l])):
						sm = self.op(sm, self.d[l])
						l += 1
				return l - self.size
			sm = self.op(sm, self.d[l])
			l += 1
			if l & -l == l:
				return self.n

	def min_left(self, r, g):
		if r == 0:
			return 0
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(r - 1 >> i)
		sm = self.e
		while True:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(self.op(self.d[r], sm)):
				while r < self.size:
					self.push(r)
					r = 2 * r + 1
					if g(self.op(self.d[r], sm)):
						sm = self.op(self.d[r], sm)
						r -= 1
				return r + 1 - self.size
			sm = self.op(self.d[r], sm)
			if r & -r == r:
				return 0
mod = 998244353

def op(x, y):
	x_val = x >> 31
	y_val = y >> 31
	dg = x - (x_val << 31) + (y - (y_val << 31))
	if x_val + y_val >= mod:
		val = x_val + y_val - mod
	else:
		val = x_val + y_val
	if dg >= mod:
		dg -= mod
	return (val << 31) + dg

def mapping(p, x):
	if p == -1:
		return x
	dg = x - (x >> 31 << 31)
	return (p * dg % mod << 31) + dg
composition = lambda p, q: q if p == -1 else p
(n, q) = map(int, input().split())
res = [0] * n
LST = LazySegmentTree(n, op, 0, mapping, composition, -1)
v = 0
ten = 1
for i in range(n):
	res[i] = (ten << 31) + ten
	ten = ten * 10 % mod
LST.build(res[::-1])
for _ in range(q):
	(l, r, D) = map(int, input().split())
	LST.range_apply(l - 1, r, D)
	print((LST.all_prod() >> 31) % mod)


import sys
input = sys.stdin.readline

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

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

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

def main():

	class LazySegmentTree:
		__slots__ = ['n', 'data', 'lazy', 'me', 'oe', 'fmm', 'fmo', 'foo']

		def __init__(self, monoid_data, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator, func_operator_operator):
			self.me = monoid_identity
			self.oe = operator_identity
			self.fmm = func_monoid_monoid
			self.fmo = func_monoid_operator
			self.foo = func_operator_operator
			self.n = len(monoid_data)
			self.data = monoid_data * 2
			for i in range(self.n - 1, 0, -1):
				self.data[i] = self.fmm(self.data[2 * i], self.data[2 * i + 1])
			self.lazy = [self.oe] * (self.n * 2)

		def replace(self, index, value):
			index += self.n
			for shift in range(index.bit_length() - 1, 0, -1):
				i = index >> shift
				self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
				self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
				self.data[i] = self.fmo(self.data[i], self.lazy[i])
				self.lazy[i] = self.oe
			self.data[index] = value
			self.lazy[index] = self.oe
			i = index
			while i > 1:
				i //= 2
				self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
				self.lazy[i] = self.oe

		def effect(self, l, r, operator):
			l += self.n
			r += self.n
			indices = []
			l0 = l // (l & -l) // 2
			r0 = (r // (r & -r) - 1) // 2
			while r0 > l0:
				indices.append(r0)
				r0 //= 2
			while l0 > r0:
				indices.append(l0)
				l0 //= 2
			while l0 and l0 != r0:
				indices.append(r0)
				r0 //= 2
				if l0 == r0:
					break
				indices.append(l0)
				l0 //= 2
			while r0:
				indices.append(r0)
				r0 //= 2
			for i in reversed(indices):
				self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
				self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
				self.data[i] = self.fmo(self.data[i], self.lazy[i])
				self.lazy[i] = self.oe
			while l < r:
				if l % 2:
					self.lazy[l] = self.foo(self.lazy[l], operator)
					l += 1
				if r % 2:
					r -= 1
					self.lazy[r] = self.foo(self.lazy[r], operator)
				l //= 2
				r //= 2
			for i in indices:
				self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
				self.lazy[i] = self.oe

		def folded(self, l, r):
			l += self.n
			r += self.n
			indices = []
			l0 = l // (l & -l) // 2
			r0 = (r // (r & -r) - 1) // 2
			while r0 > l0:
				indices.append(r0)
				r0 //= 2
			while l0 > r0:
				indices.append(l0)
				l0 //= 2
			while l0 and l0 != r0:
				indices.append(r0)
				r0 //= 2
				if l0 == r0:
					break
				indices.append(l0)
				l0 //= 2
			while r0:
				indices.append(r0)
				r0 //= 2
			for i in reversed(indices):
				self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
				self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
				self.data[i] = self.fmo(self.data[i], self.lazy[i])
				self.lazy[i] = self.oe
			left_folded = self.me
			right_folded = self.me
			while l < r:
				if l % 2:
					left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
					l += 1
				if r % 2:
					r -= 1
					right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
				l //= 2
				r //= 2
			return self.fmm(left_folded, right_folded)
	mod = 998244353
	(N, Q) = MI()
	POW = [1]
	for _ in range(N + 5):
		a = POW[-1]
		a *= 10
		a %= mod
		POW.append(a)
	inv9 = pow(9, mod - 2, mod)
	MM = 32
	mask = (1 << MM) - 1

	def enc(a, d):
		return (a << MM) + d

	def dec(v):
		a = v >> MM
		d = v & mask
		return (a, d)
	mide = enc(1, 1)
	monoid_data = [mide] * N
	monoid_ide = 0
	ope_ide = 0

	def fmm(m1, m2):
		(a1, d1) = dec(m1)
		(a2, d2) = dec(m2)
		temp = a1 * POW[d2] + a2
		return enc(temp % mod, d1 + d2)

	def fmo(m1, o1):
		if o1:
			(a1, d1) = dec(m1)
			temp = o1 * (POW[d1] - 1) * inv9
			return enc(temp % mod, d1)
		else:
			return m1

	def foo(o1, o2):
		if o2:
			return o2
		else:
			return o1
	Lseg = LazySegmentTree(monoid_data, monoid_ide, ope_ide, fmm, fmo, foo)
	for _ in range(Q):
		(l, r, d) = MI()
		l -= 1
		r -= 1
		Lseg.effect(l, r + 1, d)
		ans = Lseg.folded(0, N)
		(a, d) = dec(ans)
		print(a)
main()


class LazySegmentTree:

	def __init__(self, n, op, e, mapping, composition, id):
		self.n = n
		self.op = op
		self.e = e
		self.mapping = mapping
		self.composition = composition
		self.id = id
		self.log = (n - 1).bit_length()
		self.size = 1 << self.log
		self.data = [(e, e)] * (2 * self.size)
		self.lazy = [id] * self.size

	def update(self, k):
		self.data[k] = self.op(self.data[2 * k], self.data[2 * k + 1])

	def all_apply(self, k, f):
		self.data[k] = self.mapping(f, self.data[k])
		if k < self.size:
			self.lazy[k] = self.composition(f, self.lazy[k])

	def push(self, k):
		self.all_apply(2 * k, self.lazy[k])
		self.all_apply(2 * k + 1, self.lazy[k])
		self.lazy[k] = self.id

	def build(self, arr):
		for (i, a) in enumerate(arr):
			self.data[self.size + i] = a
		for i in range(self.size - 1, 0, -1):
			self.update(i)

	def set(self, p, x):
		p += self.size
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		self.data[p] = x
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def get(self, p):
		p += self.size
		for i in range(1, self.log + 1):
			self.push(p >> i)
		return self.data[p]

	def prod(self, l, r):
		if l == r:
			return self.e
		l += self.size
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r >> i)
		sml = smr = self.e
		while l < r:
			if l & 1:
				sml = self.op(sml, self.data[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.data[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def all_prod(self):
		return self.data[1]

	def apply(self, p, f):
		p += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(p >> i)
		self.data[p] = self.mapping(f, self.data[p])
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def range_apply(self, l, r, f):
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r - 1 >> i)
		l2 = l
		r2 = r
		while l < r:
			if l & 1:
				self.all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.all_apply(r, f)
			l >>= 1
			r >>= 1
		l = l2
		r = r2
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.update(l >> i)
			if r >> i << i != r:
				self.update(r - 1 >> i)

	def max_right(self, l, g):
		if l == self.n:
			return self.n
		l += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(l >> i)
		sm = self.e
		while True:
			while l % 2 == 0:
				l >>= 1
			if not g(self.op(sm, self.data[l])):
				while l < self.size:
					self.push(l)
					l = 2 * l
					if g(self.op(sm, self.data[l])):
						sm = self.op(sm, self.data[l])
						l += 1
				return l - self.size
			sm = self.op(sm, self.data[l])
			l += 1
			if l & -l == l:
				return self.n

	def min_left(self, r, g):
		if r == 0:
			return 0
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(r - 1 >> i)
		sm = self.e
		while True:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(self.op(self.data[r], sm)):
				while r < self.size:
					self.push(r)
					r = 2 * r + 1
					if g(self.op(self.data[r], sm)):
						sm = self.op(self.data[r], sm)
						r -= 1
				return r + 1 - self.size
			sm = self.op(self.data[r], sm)
			if r & -r == r:
				return 0
import sys
input = sys.stdin.buffer.readline
INF = 10 ** 18
MOD = 998244353
(N, Q) = map(int, input().split())

def op(x, y):
	(xv, xr) = x
	(yv, yr) = y
	return ((xv + yv) % MOD, (xr + yr) % MOD)

def mapping(p, x):
	(xv, xr) = x
	if p != INF:
		return (p * xr % MOD, xr)
	return x

def composition(p, q):
	if p != INF:
		return p
	return q
lis = [1] * N
for i in range(N - 1, 0, -1):
	lis[i - 1] = lis[i] * 10 % MOD
arr = [(e, e) for e in lis]
e = 0
id = INF
lst = LazySegmentTree(N, op, e, mapping, composition, id)
lst.build(arr)
res = list()
for _ in range(Q):
	(l, r, d) = map(int, input().split())
	lst.range_apply(l - 1, r, d)
	v = lst.all_prod()
	res.append(v[0])
print('\n'.join(map(str, res)))


class LazySegmentTree:

	def __init__(self, op_X, e_X, mapping, compose, id_M, N, array=None):
		__slots__ = ['op_X', 'e_X', 'mapping', 'compose', 'id_M', 'N', 'log', 'N0', 'data', 'lazy']
		self.e_X = e_X
		self.op_X = op_X
		self.mapping = mapping
		self.compose = compose
		self.id_M = id_M
		self.N = N
		self.log = (N - 1).bit_length()
		self.N0 = 1 << self.log
		self.data = [e_X] * (2 * self.N0)
		self.lazy = [id_M] * self.N0
		if array is not None:
			assert N == len(array)
			self.data[self.N0:self.N0 + self.N] = array
			for i in range(self.N0 - 1, 0, -1):
				self.update(i)

	def point_set(self, p, x):
		p += self.N0
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		self.data[p] = x
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def point_get(self, p):
		p += self.N0
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		return self.data[p]

	def prod(self, l, r):
		if l == r:
			return self.e_X
		l += self.N0
		r += self.N0
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r >> i)
		sml = smr = self.e_X
		while l < r:
			if l & 1:
				sml = self.op_X(sml, self.data[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op_X(self.data[r], smr)
			l >>= 1
			r >>= 1
		return self.op_X(sml, smr)

	def all_prod(self):
		return self.data[1]

	def apply(self, p, f):
		p += self.N0
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		self.data[p] = self.mapping(f, self.data[p])
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def apply(self, l, r, f):
		if l == r:
			return
		l += self.N0
		r += self.N0
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r - 1 >> i)
		(l2, r2) = (l, r)
		while l < r:
			if l & 1:
				self.all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.all_apply(r, f)
			l >>= 1
			r >>= 1
		(l, r) = (l2, r2)
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.update(l >> i)
			if r >> i << i != r:
				self.update(r - 1 >> i)

	def max_right(self, l, g):
		if l == self.N:
			return self.N
		l += self.N0
		for i in range(self.log, 0, -1):
			self.push(l >> i)
		sm = self.e_X
		while True:
			while l & 1 == 0:
				l >>= 1
			if not g(self.op_X(sm, self.data[l])):
				while l < self.N0:
					self.push(l)
					l *= 2
					if g(self.op_X(sm, self.data[l])):
						sm = self.op_X(sm, self.data[l])
						l += 1
				return l - self.N0
			sm = self.op_X(sm, self.data[l])
			l += 1
			if l & -l == l:
				break
		return self.N

	def min_left(self, r, g):
		if r == 0:
			return 0
		r += self.N0
		for i in range(self.log, 0, -1):
			self.push(r - 1 >> i)
		sm = self.e_X
		while True:
			r -= 1
			while r > 1 and r & 1:
				r >>= 1
			if not g(self.op_X(self.data[r], sm)):
				while r < self.N0:
					self.push(r)
					r = 2 * r + 1
					if g(self.op_X(self.data[r], sm)):
						sm = self.op_X(self.data[r], sm)
						r -= 1
				return r + 1 - self.N0
			sm = self.op_X(self.data[r], sm)
			if r & -r == r:
				break
		return 0

	def update(self, k):
		self.data[k] = self.op_X(self.data[2 * k], self.data[2 * k + 1])

	def all_apply(self, k, f):
		self.data[k] = self.mapping(f, self.data[k])
		if k < self.N0:
			self.lazy[k] = self.compose(f, self.lazy[k])

	def push(self, k):
		if self.lazy[k] is self.id_M:
			return
		self.data[2 * k] = self.mapping(self.lazy[k], self.data[2 * k])
		self.data[2 * k + 1] = self.mapping(self.lazy[k], self.data[2 * k + 1])
		if 2 * k < self.N0:
			self.lazy[2 * k] = self.compose(self.lazy[k], self.lazy[2 * k])
			self.lazy[2 * k + 1] = self.compose(self.lazy[k], self.lazy[2 * k + 1])
		self.lazy[k] = self.id_M
e_X = 0
id_M = 0

def op_X(X, Y):
	(x1, d1) = (X >> 32, X & MASK)
	(x2, d2) = (Y >> 32, Y & MASK)
	return ((x1 * p10[d2] + x2) % MOD << 32) + d1 + d2

def compose(f, g):
	return f

def mapping(f, X):
	if f == 0:
		return X
	else:
		(x, d) = (X >> 32, X & MASK)
		return ((p10[d] - 1) * inv9 * f % MOD << 32) + d
import sys
readline = sys.stdin.readline
MOD = 998244353
MASK = (1 << 32) - 1
inv9 = 443664157
(n, q) = map(int, readline().split())
p10 = [1] * (n + 2)
for i in range(1, n + 2):
	p10[i] = p10[i - 1] * 10 % MOD
a = [(1 << 32) + 1] * n
seg = LazySegmentTree(op_X, e_X, mapping, compose, id_M, n, array=a)
for _ in range(q):
	(l, r, d) = map(int, readline().split())
	seg.apply(l - 1, r, d)
	print(seg.all_prod() >> 32)


import sys

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

class LazySegmentTree:
	__slots__ = ['n', 'seg', 'x_unit', 'm_unit', 'f', 'g', 'h', 'lazy']

	def __init__(self, n, p, x_unit, m_unit, f, g, h):
		self.n = n
		self.seg = p * 2
		self.x_unit = x_unit
		self.m_unit = m_unit
		self.f = f
		self.g = g
		self.h = h
		for i in range(self.n - 1, 0, -1):
			self.seg[i] = self.f(self.seg[i << 1], self.seg[(i << 1) + 1])
		self.lazy = [m_unit] * (self.n * 2)

	def update(self, l, r, x):
		l += self.n
		r += self.n
		ll = l // (l & -l)
		rr = r // (r & -r) - 1
		for shift in range(ll.bit_length() - 1, 0, -1):
			i = ll >> shift
			self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
			self.lazy[(i << 1) + 1] = self.h(self.lazy[(i << 1) + 1], self.lazy[i])
			self.seg[i] = self.g(self.seg[i], self.lazy[i])
			self.lazy[i] = self.m_unit
		for shift in range(rr.bit_length() - 1, 0, -1):
			i = rr >> shift
			self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
			self.lazy[(i << 1) + 1] = self.h(self.lazy[(i << 1) + 1], self.lazy[i])
			self.seg[i] = self.g(self.seg[i], self.lazy[i])
			self.lazy[i] = self.m_unit
		while l < r:
			if l & 1:
				self.lazy[l] = self.h(self.lazy[l], x)
				l += 1
			if r & 1:
				r -= 1
				self.lazy[r] = self.h(self.lazy[r], x)
			l >>= 1
			r >>= 1
		while ll > 1:
			ll >>= 1
			self.seg[ll] = self.f(self.g(self.seg[ll << 1], self.lazy[ll << 1]), self.g(self.seg[(ll << 1) + 1], self.lazy[(ll << 1) + 1]))
			self.lazy[ll] = self.m_unit
		while rr > 1:
			rr >>= 1
			self.seg[rr] = self.f(self.g(self.seg[rr << 1], self.lazy[rr << 1]), self.g(self.seg[(rr << 1) + 1], self.lazy[(rr << 1) + 1]))
			self.lazy[rr] = self.m_unit

	def query(self, l, r):
		l += self.n
		r += self.n
		ll = l // (l & -l)
		rr = r // (r & -r) - 1
		for shift in range(ll.bit_length() - 1, 0, -1):
			i = ll >> shift
			self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
			self.lazy[(i << 1) + 1] = self.h(self.lazy[(i << 1) + 1], self.lazy[i])
			self.seg[i] = self.g(self.seg[i], self.lazy[i])
			self.lazy[i] = self.m_unit
		for shift in range(rr.bit_length() - 1, 0, -1):
			i = rr >> shift
			self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
			self.lazy[(i << 1) + 1] = self.h(self.lazy[(i << 1) + 1], self.lazy[i])
			self.seg[i] = self.g(self.seg[i], self.lazy[i])
			self.lazy[i] = self.m_unit
		ans_l = ans_r = self.x_unit
		while l < r:
			if l & 1:
				ans_l = self.f(ans_l, self.g(self.seg[l], self.lazy[l]))
				l += 1
			if r & 1:
				r -= 1
				ans_r = self.f(self.g(self.seg[r], self.lazy[r]), ans_r)
			l >>= 1
			r >>= 1
		return self.f(ans_l, ans_r)
mod = 998244353
(n, q) = map(int, input().split())
digit = [1]
for _ in range(n):
	digit.append(digit[-1] * 10 % mod)
inv9 = pow(9, mod - 2, mod)

def f(a, b):
	(asum, alen) = divmod(a, 200001)
	(bsum, blen) = divmod(b, 200001)
	return (digit[blen] * asum + bsum) % mod * 200001 + alen + blen

def g(x, y):
	if y is None:
		return x
	(_, xlen) = divmod(x, 200001)
	return (digit[xlen] - 1) * inv9 * y % mod * 200001 + xlen

def h(x, y):
	if y is None:
		return x
	return y
seg = LazySegmentTree(n, [200002] * n, 0, None, f, g, h)
for _ in range(q):
	(l, r, d) = map(int, input().split())
	seg.update(l - 1, r, d)
	print(seg.query(0, n) // 200001)


import sys
input = lambda : sys.stdin.readline().rstrip()
sys.setrecursionlimit(max(1000, 10 ** 9))
write = lambda x: sys.stdout.write(x + '\n')

class LazySegmentTree:

	def __init__(self, n, a=None):
		num = 1
		while num <= n:
			num *= 2
		self.num = num
		self.seg = [ninf] * (2 * self.num - 1)
		self.lazy = [f0] * (2 * self.num - 1)
		self.ls = [0] * (2 * self.num - 1)
		self.rs = [0] * (2 * self.num - 1)
		self.ls[0] = 0
		self.rs[0] = self.num
		for i in range(self.num - 1):
			self.ls[2 * i + 1] = self.ls[i]
			self.rs[2 * i + 1] = (self.ls[i] + self.rs[i]) // 2
			self.ls[2 * i + 2] = (self.ls[i] + self.rs[i]) // 2
			self.rs[2 * i + 2] = self.rs[i]
		if a is not None:
			assert len(a) == n
			for i in range(n):
				self.seg[num - 1 + i] = a[i]
			for k in range(num - 2, -1, -1):
				self.seg[k] = op(self.seg[2 * k + 1], self.seg[2 * k + 2])

	def eval(self, k):
		if self.lazy[k] == f0:
			return
		if k < self.num - 1:
			self.lazy[k * 2 + 1] = composition(self.lazy[k], self.lazy[k * 2 + 1])
			self.lazy[k * 2 + 2] = composition(self.lazy[k], self.lazy[k * 2 + 2])
		self.seg[k] = mapping(self.lazy[k], self.seg[k])
		self.lazy[k] = f0

	def eval_all(self):
		for i in range(2 * self.num - 1):
			self.eval(i)

	def update(self, a, b, x=None, f=None):
		if f is None:
			f = lambda y: x
		k = 0
		q = [k]
		while q:
			k = q.pop()
			(l, r) = (self.ls[k], self.rs[k])
			if k >= 0:
				self.eval(k)
				if r <= a or b <= l:
					continue
				elif a <= l and r <= b:
					self.lazy[k] = composition(f, self.lazy[k])
					self.eval(k)
				else:
					q.append(~k)
					q.append(2 * k + 1)
					q.append(2 * k + 2)
			else:
				k = ~k
				self.seg[k] = op(self.seg[2 * k + 1], self.seg[2 * k + 2])

	def query(self, a, b):
		k = 0
		l = 0
		r = self.num
		q = [k]
		ans = ninf
		while q:
			k = q.pop()
			(l, r) = (self.ls[k], self.rs[k])
			self.eval(k)
			if r <= a or b <= l:
				continue
			elif a <= l and r <= b:
				ans = op(ans, self.seg[k])
			else:
				q.append(2 * k + 2)
				q.append(2 * k + 1)
		return ans
(n, q) = list(map(int, input().split()))
M = 998244353
vals = [1]
vals2 = [1]
v = 1
for i in range(n):
	v *= 10
	v %= M
	vals.append(v)
	vals2.append((1 + vals2[-1] * 10) % M)
ninf = 0
V = 1 << 32

def op(x, y):
	return (x % V * vals[y // V] + y % V) % M + (x // V + y // V) * V
mapping = lambda f, x: x if f is None else f % 10 * vals2[x // V - 1] % M + x // V * V

def composition(f1, f2):
	if f1 is None:
		return f2
	elif f2 is None:
		return f1
	elif f1 // 10 < f2 // 10:
		return f2
	else:
		return f1
f0 = None
sg = LazySegmentTree(n, [1 + (1 << 32)] * n)
ans = [None] * q
for i in range(q):
	(l, r, d) = map(int, input().split())
	l -= 1
	r -= 1
	sg.update(l, r + 1, f=10 * i + d)
	ans[i] = sg.query(0, n + 1) % V
write('\n'.join(map(str, ans)))


class LazySegmentTree:
	__slots__ = ['n', 'data', 'lazy', 'me', 'oe', 'fmm', 'fmo', 'foo']

	def __init__(self, monoid_data, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator, func_operator_operator):
		self.me = monoid_identity
		self.oe = operator_identity
		self.fmm = func_monoid_monoid
		self.fmo = func_monoid_operator
		self.foo = func_operator_operator
		self.n = len(monoid_data)
		self.data = monoid_data * 2
		for i in range(self.n - 1, 0, -1):
			self.data[i] = self.fmm(self.data[2 * i], self.data[2 * i + 1])
		self.lazy = [self.oe] * (self.n * 2)

	def replace(self, index, value):
		index += self.n
		for shift in range(index.bit_length() - 1, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		self.data[index] = value
		self.lazy[index] = self.oe
		i = index
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def effect(self, l, r, operator):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 //= 2
		while l0 > r0:
			indices.append(l0)
			l0 //= 2
		while l0 and l0 != r0:
			indices.append(r0)
			r0 //= 2
			if l0 == r0:
				break
			indices.append(l0)
			l0 //= 2
		while r0:
			indices.append(r0)
			r0 //= 2
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		while l < r:
			if l % 2:
				self.lazy[l] = self.foo(self.lazy[l], operator)
				l += 1
			if r % 2:
				r -= 1
				self.lazy[r] = self.foo(self.lazy[r], operator)
			l //= 2
			r //= 2
		for i in indices:
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def folded(self, l, r):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 //= 2
		while l0 > r0:
			indices.append(l0)
			l0 //= 2
		while l0 and l0 != r0:
			indices.append(r0)
			r0 //= 2
			if l0 == r0:
				break
			indices.append(l0)
			l0 //= 2
		while r0:
			indices.append(r0)
			r0 //= 2
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		left_folded = self.me
		right_folded = self.me
		while l < r:
			if l % 2:
				left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
				l += 1
			if r % 2:
				r -= 1
				right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
			l //= 2
			r //= 2
		return self.fmm(left_folded, right_folded)
(N, Q) = map(int, input().split())
(l, r, d) = (0, 0, 0)
mod = 998244353
P = [1] * (10 ** 6 + 1)
for i in range(10 ** 6):
	P[i + 1] = P[i] * 10 % mod
inv9 = pow(9, mod - 2, mod)

def f(x, y):
	if x == (0, 0):
		return y
	if y == (0, 0):
		return x
	return ((x[0] * P[y[1]] + y[0]) % mod, x[1] + y[1])

def g(x, y):
	if y != -1:
		return ((P[x[1]] - 1) * y * inv9 % mod, x[1])
	else:
		return x

def h(x, y):
	if y == -1 and x != -1:
		return x
	return y
n = 1
while n < N:
	n <<= 1
Y = n - N
X = LazySegmentTree([(0, 1) if i < Y else (1, 1) for i in range(n)], (0, 0), -1, f, g, h)
for i in range(Q):
	(l, r, d) = map(int, input().split())
	l += Y - 1
	r += Y
	X.effect(l, r, d)
	print(X.folded(0, n)[0])


from typing import Callable, List, TypeVar
S = TypeVar('S')
F = TypeVar('F')

class LazySegmentTree:
	__slots__ = ['e', 'op', 'id', 'mapping', 'composition', '_n', '_log', '_size', 'tree', 'lazy']

	def __init__(self, a: List[S], e: S, op: Callable[[S, S], S], id_: F, mapping: Callable[[F, S], S], composition: Callable[[F, F], F]) -> None:
		self.e = e
		self.op = op
		self.id = id_
		self.mapping = mapping
		self.composition = composition
		self._n = len(a)
		self._log = (self._n - 1).bit_length()
		self._size = 1 << self._log
		self.tree = [e] * self._size + a + [e] * (self._size - self._n)
		for i in range(self._size - 1, 0, -1):
			self._update(i)
		self.lazy = [id_] * self._size

	def _update(self, k: int) -> None:
		self.tree[k] = self.op(self.tree[2 * k], self.tree[2 * k + 1])

	def _apply_all(self, k: int, f: F) -> None:
		self.tree[k] = self.mapping(f, self.tree[k])
		if k < self._size:
			self.lazy[k] = self.composition(f, self.lazy[k])

	def _push(self, k: int) -> None:
		self._apply_all(2 * k, self.lazy[k])
		self._apply_all(2 * k + 1, self.lazy[k])
		self.lazy[k] = self.id

	def set(self, k: int, x: S) -> None:
		assert 0 <= k < self._n
		k += self._size
		for i in range(self._log, 0, -1):
			self._push(k >> i)
		self.tree[k] = x
		for i in range(1, self._log + 1):
			self._update(k >> i)

	def get(self, k: int) -> S:
		assert 0 <= k < self._n
		k += self._size
		for i in range(self._log, 0, -1):
			self._push(k >> i)
		return self.tree[k]

	def prod(self, l: int, r: int) -> S:
		assert 0 <= l <= r <= self._n
		if l == r:
			return self.e
		l += self._size
		r += self._size
		for i in range(self._log, 0, -1):
			if l >> i << i != l:
				self._push(l >> i)
			if r >> i << i != r:
				self._push(r >> i)
		(sml, smr) = (self.e, self.e)
		while l < r:
			if l & 1:
				sml = self.op(sml, self.tree[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.tree[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def prod_all(self) -> S:
		return self.tree[1]

	def apply(self, k: int, f: F) -> None:
		assert 0 <= k < self._n
		k += self._size
		for i in range(self._log, 0, -1):
			self._push(k >> i)
		self.tree[k] = self.mapping(f, self.tree[k])
		for i in range(1, self._log + 1):
			self._update(k >> i)

	def apply_range(self, l: int, r: int, f: F) -> None:
		assert 0 <= l <= r <= self._n
		if l == r:
			return
		l += self._size
		r += self._size
		for i in range(self._log, 0, -1):
			if l >> i << i != l:
				self._push(l >> i)
			if r >> i << i != r:
				self._push(r - 1 >> i)
		(l_tmp, r_tmp) = (l, r)
		while l < r:
			if l & 1:
				self._apply_all(l, f)
				l += 1
			if r & 1:
				r -= 1
				self._apply_all(r, f)
			l >>= 1
			r >>= 1
		(l, r) = (l_tmp, r_tmp)
		for i in range(1, self._log + 1):
			if l >> i << i != l:
				self._update(l >> i)
			if r >> i << i != r:
				self._update(r - 1 >> i)
(N, Q) = map(int, input().split())
MOD = 998244353
MASK = 1 << 32
base = [MASK + 1] * N
tens = [0] * (N + 1)
tens[0] = 1
for i in range(1, N + 1):
	tens[i] = tens[i - 1] * 10 % MOD
ones = [0] * (N + 1)
ones[1] = 1
for i in range(2, N + 1):
	ones[i] = (ones[i - 1] * 10 + 1) % MOD

def op(l, r):
	(l0, l1) = (l >> 32, l % MASK)
	(r0, r1) = (r >> 32, r % MASK)
	return ((l0 * tens[r1] + r0) % MOD << 32) + (l1 + r1)

def mapping(l, r):
	if l == 0:
		return r
	(r0, r1) = (r >> 32, r % MASK)
	return (l * ones[r1] % MOD << 32) + r1

def composition(l, r):
	if l == 0:
		return r
	return l
seg = LazySegmentTree(base, 0, op, 0, mapping, composition)
for i in range(Q):
	(L, R, D) = map(int, input().split())
	seg.apply_range(L - 1, R, D)
	print(seg.prod_all() >> 32)


import sys
input = sys.stdin.readline
MOD = 998244353
e = 0
id_x = -1

def op(a, b):
	(a1, a2) = (a >> 32, a % (1 << 32))
	(b1, b2) = (b >> 32, b % (1 << 32))
	c1 = (a1 + b1) % MOD
	c2 = (a2 + b2) % MOD
	return (c1 << 32) + c2

def mapping(x, a):
	if x == -1:
		return a
	(a1, a2) = (a >> 32, a % (1 << 32))
	c1 = x * a2 % MOD
	c2 = a2
	return (c1 << 32) + c2

def composition(x, y):
	if x == -1:
		return y
	return x

def update(k):
	d[k] = op(d[2 * k], d[2 * k + 1])

def all_apply(k, f):
	d[k] = mapping(f, d[k])
	if k < size:
		lz[k] = composition(f, lz[k])

def push(k):
	all_apply(2 * k, lz[k])
	all_apply(2 * k + 1, lz[k])
	lz[k] = id_x

def build(arr):
	assert len(arr) == n
	for j in range(n):
		d[size + j] = arr[j]
	for j in range(1, size)[::-1]:
		update(j)

def set(p, x):
	assert 0 <= p < n
	p += size
	for i in range(1, log + 1)[::-1]:
		push(p >> i)
	d[p] = x
	for i in range(1, log + 1):
		update(p >> i)

def get(p):
	assert 0 <= p < n
	p += size
	for i in range(1, log + 1):
		push(p >> i)
	return d[p]

def prod(l, r):
	assert 0 <= l <= r <= n
	if l == r:
		return e
	l += size
	r += size
	for i in range(1, log + 1)[::-1]:
		if l >> i << i != l:
			push(l >> i)
		if r >> i << i != r:
			push(r >> i)
	sml = smr = e
	while l < r:
		if l & 1:
			sml = op(sml, d[l])
			l += 1
		if r & 1:
			r -= 1
			smr = op(d[r], smr)
		l >>= 1
		r >>= 1
	return op(sml, smr)

def all_prod():
	return d[1]

def apply(p, f):
	assert 0 <= p < n
	p += size
	for i in range(1, log + 1)[::-1]:
		push(p >> i)
	d[p] = mapping(f, d[p])
	for i in range(1, log + 1):
		update(p >> i)

def range_apply(l, r, f):
	assert 0 <= l <= r <= n
	if l == r:
		return
	l += size
	r += size
	for i in range(1, log + 1)[::-1]:
		if l >> i << i != l:
			push(l >> i)
		if r >> i << i != r:
			push(r - 1 >> i)
	l2 = l
	r2 = r
	while l < r:
		if l & 1:
			all_apply(l, f)
			l += 1
		if r & 1:
			r -= 1
			all_apply(r, f)
		l >>= 1
		r >>= 1
	l = l2
	r = r2
	for i in range(1, log + 1):
		if l >> i << i != l:
			update(l >> i)
		if r >> i << i != r:
			update(r - 1 >> i)

def max_right(l, g):
	assert 0 <= l <= n
	if l == n:
		return n
	l += size
	for i in range(1, log + 1)[::-1]:
		push(l >> i)
	sm = e
	while True:
		while l % 2 == 0:
			l >>= 1
		if not g(op(sm, d[l])):
			while l < size:
				push(l)
				l = 2 * l
				if g(op(sm, d[l])):
					sm = op(sm, d[l])
					l += 1
			return l - size
		sm = op(sm, d[l])
		l += 1
		if l & -l == l:
			return n

def min_left(r, g):
	assert 0 <= r <= n
	assert g(e)
	if r == 0:
		return 0
	r += size
	for i in range(1, log + 1)[::-1]:
		push(r - 1 >> i)
	sm = e
	while True:
		r -= 1
		while r > 1 and r % 2:
			r >>= 1
		if not g(op(d[r], sm)):
			while r < size:
				push(r)
				r = 2 * r + 1
				if g(op(d[r], sm)):
					sm = op(d[r], sm)
					r -= 1
			return r + 1 - size
		sm = op(d[r], sm)
		if r & -r == r:
			return 0
(n, q) = map(int, input().split())
log = (n - 1).bit_length()
size = 1 << log
d = [e] * (2 * size)
lz = [id_x] * size
A = [0] * n
tmp = 1
for i in range(n - 1, -1, -1):
	A[i] = (tmp << 32) + tmp
	tmp *= 10
	tmp %= MOD
build(A)
ans = [0] * q
for i in range(q):
	(x, y, rep) = map(int, input().split())
	range_apply(x - 1, y, rep)
	ans[i] = all_prod() >> 32
print('\n'.join(map(str, ans)))


class LazySegmentTree:
	__slots__ = ['n', 'data', 'lazy', 'me', 'oe', 'fmm', 'fmo', 'foo']

	def __init__(self, monoid_data, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator, func_operator_operator):
		self.me = monoid_identity
		self.oe = operator_identity
		self.fmm = func_monoid_monoid
		self.fmo = func_monoid_operator
		self.foo = func_operator_operator
		self.n = len(monoid_data)
		self.data = monoid_data * 2
		for i in range(self.n - 1, 0, -1):
			self.data[i] = self.fmm(self.data[2 * i], self.data[2 * i + 1])
		self.lazy = [self.oe] * (self.n * 2)

	def replace(self, index, value):
		index += self.n
		for shift in range(index.bit_length() - 1, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		self.data[index] = value
		self.lazy[index] = self.oe
		i = index
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def effect(self, l, r, operator):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 //= 2
		while l0 > r0:
			indices.append(l0)
			l0 //= 2
		while l0 and l0 != r0:
			indices.append(r0)
			r0 //= 2
			if l0 == r0:
				break
			indices.append(l0)
			l0 //= 2
		while r0:
			indices.append(r0)
			r0 //= 2
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		while l < r:
			if l % 2:
				self.lazy[l] = self.foo(self.lazy[l], operator)
				l += 1
			if r % 2:
				r -= 1
				self.lazy[r] = self.foo(self.lazy[r], operator)
			l //= 2
			r //= 2
		for i in indices:
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def folded(self, l, r):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 //= 2
		while l0 > r0:
			indices.append(l0)
			l0 //= 2
		while l0 and l0 != r0:
			indices.append(r0)
			r0 //= 2
			if l0 == r0:
				break
			indices.append(l0)
			l0 //= 2
		while r0:
			indices.append(r0)
			r0 //= 2
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		left_folded = self.me
		right_folded = self.me
		while l < r:
			if l % 2:
				left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
				l += 1
			if r % 2:
				r -= 1
				right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
			l //= 2
			r //= 2
		return self.fmm(left_folded, right_folded)
mod = 998244353
(N, Q) = map(int, input().split())
monoid_data = [(1, 1) for _ in range(N)]
ones = [0, 1]
pow10 = [1]
for i in range(N):
	ones.append((ones[-1] * 10 + 1) % mod)
	pow10.append(pow10[-1] * 10 % mod)

def fmm(m1, m2):
	return ((m1[0] * pow10[m2[1]] + m2[0]) % mod, m1[1] + m2[1])

def fmo(m1, o1):
	if o1 != -1:
		return (ones[m1[1]] * o1 % mod, m1[1])
	else:
		return m1

def foo(o1, o2):
	if o2 == -1:
		return o1
	else:
		return o2
lst = LazySegmentTree(monoid_data, (0, 0), -1, fmm, fmo, foo)
for i in range(Q):
	(l, r, d) = map(int, input().split())
	lst.effect(l - 1, r, d)
	print(lst.folded(0, N)[0])


import sys
sysread = sys.stdin.buffer.readline
read = sys.stdin.buffer.read
printout = sys.stdout.write
sprint = sys.stdout.flush
sys.setrecursionlimit(10 ** 7)
import math
INF = 1 << 50
EPS = 1e-08
mod = 998244353

def intread():
	return int(sysread())

def mapline(t=int):
	return map(t, sysread().split())

def mapread(t=int):
	return map(t, read().split())

class BIT:

	def __init__(self, n, init=0, init_val=None):
		self.n = n
		self.init = init
		self.k = n.bit_length()
		self.bins = [init] * (n + 1)
		self.l2 = 2 ** self.k
		if init_val != None:
			self.update_set(init_val)

	def update_set(self, vals):
		if len(vals) > self.n:
			raise ValueError('Length is too long!')
		for (i, val) in enumerate(vals):
			bi = i + 1
			if bi & 1:
				self.bins[bi] = val
			else:
				ret = self.init
				most_sig = bi & -bi
				n_bit = bi - 1
				while n_bit:
					v = n_bit & -n_bit
					if most_sig >= v:
						break
					ret = self.compare(ret, self.bins[n_bit])
					n_bit -= v
				self.bins[bi] = ret

	def compare(self, l, r):
		return l + r

	def minus(self, val):
		return -val

	def update(self, idx, by):
		while idx < len(self.bins):
			self.bins[idx] = self.compare(self.bins[idx], by)
			idx += idx & -idx

	def get_sum(self, idx):
		ans = self.init
		while idx:
			ans = self.compare(ans, self.bins[idx])
			idx -= idx & -idx
		return ans

	def eval_between(self, l, r):
		return self.compare(self.get_sum(r), self.get_sum(self.get_sum(l - 1)))

	def lower_bound(self, SUM):
		if SUM <= 0:
			return 0
		l = 0
		r = self.l2
		while r > 0:
			if l + r <= self.n and self.bins[l + r] < SUM:
				SUM -= self.bins[l + r]
				l += r
			r >>= 1
		return l + 1

	def upper_bound(self, SUM):
		l = 0
		r = self.l2
		while r > 0:
			if l + r <= self.n and self.bins[l + r] <= SUM:
				SUM -= self.bins[l + r]
				l += r
			r >>= 1
		return l + 1

class std_map:

	def __init__(self, n, init):
		self.size = n
		self.keys = set()
		self.bit = BIT(n + 1)
		self.dic = [init] * (n + 1)

	def __contains__(self, key):
		return key in self.keys

	def __getitem__(self, key):
		return self.dic[key]

	def __setitem__(self, key, value):
		if not key in self.keys:
			self.bit.update(key, 1)
			self.keys.add(key)
		self.dic[key] = value

	def remove(self, key):
		self.keys.remove(key)
		self.bit.update(key, -1)

	def lower_bound(self, k):
		return self.bit.lower_bound(self.bit.get_sum(k))

	def upper_bound(self, k):
		return self.bit.upper_bound(self.bit.get_sum(k))

	def kth_key(self, k):
		return self.bit.lower_bound(k)

	def kth_value(self, k):
		return self.dic[self.kth_key(k)]

	def prev_k(self, k):
		idx = self.bit.get_sum(k)
		if idx == 0:
			return -1
		return self.bit.lower_bound(idx - 1)

def pow_mod(x, k, mod):
	ret = [1]
	a = 1
	for i in range(k):
		a *= x
		a %= mod
		ret.append(a)
	return ret

def run():
	(N, Q) = mapline()
	m = std_map(N, init=-1)
	m[1] = (N, 1)
	powmod = pow_mod(10, N - 1, mod)
	summod = [0]
	t = 0
	for p in powmod:
		t += p
		summod.append(t)
	ans = summod[N]
	for i in range(Q):
		(l, r, d) = mapline()
		s = m.lower_bound(l - 1)
		if s > 0:
			(rr, dd) = m[s]
			if l <= rr:
				ans -= summod[rr - s + 1] * powmod[N - rr] * dd
				ans %= mod
				m[s] = (l - 1, dd)
				ans += summod[l - s] * powmod[N - l + 1] * dd
				ans %= mod
				if r < rr:
					m[l] = (r, d)
					ans += summod[r - l + 1] * powmod[N - r] * d
					ans %= mod
					m[r + 1] = (rr, dd)
					ans += summod[rr - r] * powmod[N - rr] * dd
					ans %= mod
					print(ans)
					continue
		k = l - 1
		while True:
			s = m.upper_bound(k)
			if s == N + 1:
				break
			if s <= r:
				(rr, dd) = m[s]
				m.remove(s)
				ans -= summod[rr - s + 1] * powmod[N - rr] * dd
				ans %= mod
				if rr > r:
					m[r + 1] = (rr, dd)
					ans += summod[rr - r] * powmod[N - rr] * dd
					ans %= mod
					break
				k = rr
			else:
				break
		m[l] = (r, d)
		ans += summod[r - l + 1] * powmod[N - r] * d
		ans %= mod
		print(ans)
run()


import sys
input = sys.stdin.readline
sys.setrecursionlimit(1000000)
import math
import bisect
import heapq
from collections import defaultdict
from collections import deque
from collections import Counter
from functools import lru_cache
MOD = 998244353
INF = float('inf')
AZ = 'abcdefghijklmnopqrstuvwxyz'

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

def S():
	return input().strip()

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

def SL():
	return list(map(str, input().split()))

def ILs(n):
	return list((int(input()) for _ in range(n)))

def SLs(n):
	return list((input().strip() for _ in range(n)))

def ILL(n):
	return [list(map(int, input().split())) for _ in range(n)]

def SLL(n):
	return [list(map(str, input().split())) for _ in range(n)]

def DD(arg):
	return defaultdict(arg)

def inv(n):
	return pow(n, MOD - 2, MOD)
kaijo_memo = []

def kaijo(n):
	if len(kaijo_memo) > n:
		return kaijo_memo[n]
	if len(kaijo_memo) == 0:
		kaijo_memo.append(1)
	while len(kaijo_memo) <= n:
		kaijo_memo.append(kaijo_memo[-1] * len(kaijo_memo) % MOD)
	return kaijo_memo[n]
gyaku_kaijo_memo = []

def gyaku_kaijo(n):
	if len(gyaku_kaijo_memo) > n:
		return gyaku_kaijo_memo[n]
	if len(gyaku_kaijo_memo) == 0:
		gyaku_kaijo_memo.append(1)
	while len(gyaku_kaijo_memo) <= n:
		gyaku_kaijo_memo.append(gyaku_kaijo_memo[-1] * pow(len(gyaku_kaijo_memo), MOD - 2, MOD) % MOD)
	return gyaku_kaijo_memo[n]

def nCr(n, r):
	if n == r:
		return 1
	if n < r or r < 0:
		return 0
	ret = 1
	ret = ret * kaijo(n) % MOD
	ret = ret * gyaku_kaijo(r) % MOD
	ret = ret * gyaku_kaijo(n - r) % MOD
	return ret

def factorization(n):
	arr = []
	temp = n
	for i in range(2, int(-(-n ** 0.5 // 1)) + 1):
		if temp % i == 0:
			cnt = 0
			while temp % i == 0:
				cnt += 1
				temp //= i
			arr.append([i, cnt])
	if temp != 1:
		arr.append([temp, 1])
	if arr == []:
		arr.append([n, 1])
	return arr

def make_divisors(n):
	divisors = []
	for i in range(1, int(n ** 0.5) + 1):
		if n % i == 0:
			divisors.append(i)
			if i != n // i:
				divisors.append(n // i)
	return divisors

def make_primes(N):
	max = int(math.sqrt(N))
	seachList = [i for i in range(2, N + 1)]
	primeNum = []
	while seachList[0] <= max:
		primeNum.append(seachList[0])
		tmp = seachList[0]
		seachList = [i for i in seachList if i % tmp != 0]
	primeNum.extend(seachList)
	return primeNum

def gcd(a, b):
	while b:
		(a, b) = (b, a % b)
	return a

def lcm(a, b):
	return a * b // gcd(a, b)

def count_bit(n):
	count = 0
	while n:
		n &= n - 1
		count += 1
	return count

def base_10_to_n(X, n):
	if X // n:
		return base_10_to_n(X // n, n) + [X % n]
	return [X % n]

def base_n_to_10(X, n):
	return sum((int(str(X)[-i - 1]) * n ** i for i in range(len(str(X)))))

def base_10_to_n_without_0(X, n):
	X -= 1
	if X // n:
		return base_10_to_n_without_0(X // n, n) + [X % n]
	return [X % n]

def int_log(n, a):
	count = 0
	while n >= a:
		n //= a
		count += 1
	return count
(N, Q) = IL()
base = 10 ** 6

class RUQ:

	def __init__(self, N, default=None):
		self.N0 = 2 ** (N - 1).bit_length()
		self.data = [(-1, default)] * (2 * self.N0)
		self.INF = (-1, default)

	def update(self, l, r, v):
		L = l + self.N0
		R = r + self.N0
		while L < R:
			if R & 1:
				R -= 1
				self.data[R - 1] = v
			if L & 1:
				self.data[L - 1] = v
				L += 1
			L >>= 1
			R >>= 1

	def _query(self, k):
		k += self.N0 - 1
		s = self.INF
		while k >= 0:
			if self.data[k]:
				s = max(s, self.data[k])
			k = (k - 1) // 2
		return s

	def query(self, k):
		temp = self._query(k)[1]
		return (temp // base ** 2, temp % base ** 2 // base, temp % base)
ST = RUQ(220000, 1 * base ** 2 + 1 * base + N)
ichiga = [0]
for _ in range(N):
	ichiga.append((ichiga[-1] * 10 + 1) % MOD)
ans = ichiga[-1]
for i in range(Q):
	(l, r, d) = IL()
	p = l
	while p <= r:
		(x, f, t) = ST.query(p)
		ans -= (ichiga[N - p + 1] - ichiga[N - min(t, r)]) * x
		ans %= MOD
		p = t + 1
	(x, f, t) = ST.query(l)
	ST.update(f, l, (i * 3, x * base ** 2 + f * base + l - 1))
	(x, f, t) = ST.query(r)
	ST.update(r + 1, t + 1, (i * 3 + 1, x * base ** 2 + (r + 1) * base + t))
	ST.update(l, r + 1, (i * 3 + 2, d * base ** 2 + l * base + r))
	ans += (ichiga[N - l + 1] - ichiga[N - r]) * d
	ans %= MOD
	print(ans)


import sys

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

class LazySegmentTree:
	__slots__ = ['n', 'num', 'seg', 'x_unit', 'm_unit', 'f', 'g', 'h', 'lazy']

	def __init__(self, n, p, x_unit, m_unit, f, g, h):
		self.n = n
		self.num = 2 ** (n - 1).bit_length()
		self.seg = p * 2
		self.x_unit = x_unit
		self.m_unit = m_unit
		self.f = f
		self.g = g
		self.h = h
		for i in range(self.n - 1, 0, -1):
			self.seg[i] = self.f(self.seg[i << 1], self.seg[(i << 1) + 1])
		self.lazy = [m_unit] * (self.n * 2)

	def update(self, l, r, x):
		l += self.num
		r += self.num
		ll = l // (l & -l)
		rr = r // (r & -r) - 1
		for shift in range(ll.bit_length() - 1, 0, -1):
			i = ll >> shift
			self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
			self.lazy[(i << 1) + 1] = self.h(self.lazy[(i << 1) + 1], self.lazy[i])
			self.seg[i] = self.g(self.seg[i], self.lazy[i], i)
			self.lazy[i] = self.m_unit
		for shift in range(rr.bit_length() - 1, 0, -1):
			i = rr >> shift
			self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
			self.lazy[(i << 1) + 1] = self.h(self.lazy[(i << 1) + 1], self.lazy[i])
			self.seg[i] = self.g(self.seg[i], self.lazy[i], i)
			self.lazy[i] = self.m_unit
		while l < r:
			if l & 1:
				self.lazy[l] = self.h(self.lazy[l], x)
				l += 1
			if r & 1:
				r -= 1
				self.lazy[r] = self.h(self.lazy[r], x)
			l >>= 1
			r >>= 1
		while ll > 1:
			ll >>= 1
			self.seg[ll] = self.f(self.g(self.seg[ll << 1], self.lazy[ll << 1], ll << 1), self.g(self.seg[(ll << 1) + 1], self.lazy[(ll << 1) + 1], (ll << 1) + 1))
			self.lazy[ll] = self.m_unit
		while rr > 1:
			rr >>= 1
			self.seg[rr] = self.f(self.g(self.seg[rr << 1], self.lazy[rr << 1], rr << 1), self.g(self.seg[(rr << 1) + 1], self.lazy[(rr << 1) + 1], (rr << 1) + 1))
			self.lazy[rr] = self.m_unit

	def query(self, l, r):
		l += self.num
		r += self.num
		ll = l // (l & -l)
		rr = r // (r & -r) - 1
		for shift in range(ll.bit_length() - 1, 0, -1):
			i = ll >> shift
			self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
			self.lazy[(i << 1) + 1] = self.h(self.lazy[(i << 1) + 1], self.lazy[i])
			self.seg[i] = self.g(self.seg[i], self.lazy[i], i)
			self.lazy[i] = self.m_unit
		for shift in range(rr.bit_length() - 1, 0, -1):
			i = rr >> shift
			self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
			self.lazy[(i << 1) + 1] = self.h(self.lazy[(i << 1) + 1], self.lazy[i])
			self.seg[i] = self.g(self.seg[i], self.lazy[i], i)
			self.lazy[i] = self.m_unit
		ans_l = ans_r = self.x_unit
		while l < r:
			if l & 1:
				ans_l = self.f(ans_l, self.g(self.seg[l], self.lazy[l], l))
				l += 1
			if r & 1:
				r -= 1
				ans_r = self.f(self.g(self.seg[r], self.lazy[r], r), ans_r)
			l >>= 1
			r >>= 1
		return self.f(ans_l, ans_r)
mod = 998244353
(n, q) = map(int, input().split())
num = 2 ** (n - 1).bit_length()
d = [1]
for i in range(n - 1):
	d.append(d[-1] * 10 % mod)
d = d[::-1]
d += [0] * (num - len(d))
e = [0] + d[:]
for i in range(num):
	e[i + 1] = (e[i] + e[i + 1]) % mod

def f(a, b):
	return a + b

def g(x, y, i):
	if y == None:
		return x
	b = 1 << i.bit_length() - 1
	i -= b
	l = num // b * i
	r = l + num // b
	return (e[r] - e[l]) * y % mod

def h(x, y):
	if y == None:
		return x
	return y
seg = LazySegmentTree(num, d, 0, None, f, g, h)
for _ in range(q):
	(l, r, d) = map(int, input().split())
	seg.update(l - 1, r, d)
	print(seg.query(0, n) % mod)


import sys
input = sys.stdin.buffer.readline
MOD = 998244353
INF = 2 * 10 ** 18
in_n = lambda : int(input())
in_nn = lambda : map(int, input().split())
in_s = lambda : input().rstrip().decode('utf-8')
in_map = lambda : [s == ord('.') for s in input() if s != ord('\n')]
e = 0
id = -1

def op(a, b):
	(a1, a2) = (a >> 32, a % (1 << 32))
	(b1, b2) = (b >> 32, b % (1 << 32))
	c1 = (a1 + b1) % MOD
	c2 = (a2 + b2) % MOD
	return (c1 << 32) + c2

def mapping(x, a):
	if x == -1:
		return a
	(a1, a2) = (a >> 32, a % (1 << 32))
	c1 = x * a2 % MOD
	c2 = a2
	return (c1 << 32) + c2

def composition(x, y):
	if x == -1:
		return y
	return x

class LazySegmentTree:

	def __init__(self, n, op, e, mapping, composition, id):
		self.n = n
		self.op = op
		self.e = e
		self.mapping = mapping
		self.composition = composition
		self.id = id
		self.log = (n - 1).bit_length()
		self.size = 1 << self.log
		self.d = [e] * (2 * self.size)
		self.lz = [id] * self.size

	def update(self, k):
		self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])

	def all_apply(self, k, f):
		self.d[k] = self.mapping(f, self.d[k])
		if k < self.size:
			self.lz[k] = self.composition(f, self.lz[k])

	def push(self, k):
		self.all_apply(2 * k, self.lz[k])
		self.all_apply(2 * k + 1, self.lz[k])
		self.lz[k] = self.id

	def build(self, arr):
		for i in range(self.n):
			self.d[self.size + i] = arr[i]
		for i in range(1, self.size)[::-1]:
			self.update(i)

	def set(self, p, x):
		p += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(p >> i)
		self.d[p] = x
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def get(self, p):
		p += self.size
		for i in range(1, self.log + 1):
			self.push(p >> i)
		return self.d[p]

	def prod(self, l, r):
		if l == r:
			return self.e
		l += self.size
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r >> i)
		sml = smr = self.e
		while l < r:
			if l & 1:
				sml = self.op(sml, self.d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.d[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def all_prod(self):
		return self.d[1]

	def apply(self, p, f):
		p += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(p >> i)
		self.d[p] = self.mapping(f, self.d[p])
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def range_apply(self, l, r, f):
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r - 1 >> i)
		l2 = l
		r2 = r
		while l < r:
			if l & 1:
				self.all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.all_apply(r, f)
			l >>= 1
			r >>= 1
		l = l2
		r = r2
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.update(l >> i)
			if r >> i << i != r:
				self.update(r - 1 >> i)

	def max_right(self, l, g):
		if l == self.n:
			return self.n
		l += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(l >> i)
		sm = self.e
		while True:
			while l % 2 == 0:
				l >>= 1
			if not g(self.op(sm, self.d[l])):
				while l < self.size:
					self.push(l)
					l = 2 * l
					if g(self.op(sm, self.d[l])):
						sm = self.op(sm, self.d[l])
						l += 1
				return l - self.size
			sm = self.op(sm, self.d[l])
			l += 1
			if l & -l == l:
				return self.n

	def min_left(self, r, g):
		if r == 0:
			return 0
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(r - 1 >> i)
		sm = self.e
		while True:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(self.op(self.d[r], sm)):
				while r < self.size:
					self.push(r)
					r = 2 * r + 1
					if g(self.op(self.d[r], sm)):
						sm = self.op(self.d[r], sm)
						r -= 1
				return r + 1 - self.size
			sm = self.op(self.d[r], sm)
			if r & -r == r:
				return 0

def main():
	(N, Q) = in_nn()
	A = [0] * N
	tmp = 1
	for i in range(N - 1, -1, -1):
		A[i] = (tmp << 32) + tmp
		tmp *= 10
		tmp %= MOD
	seg = LazySegmentTree(N, op, e, mapping, composition, id)
	seg.build(A)
	ans = [0] * Q
	for i in range(Q):
		(l, r, d) = in_nn()
		l -= 1
		seg.range_apply(l, r, d)
		ans[i] = seg.all_prod() >> 32
	print('\n'.join(map(str, ans)))
main()


class LazySegmentTree:
	__slots__ = ['n', 'data', 'lazy', 'me', 'oe', 'fmm', 'fmo', 'foo']

	def __init__(self, monoid_data, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator, func_operator_operator):
		self.me = monoid_identity
		self.oe = operator_identity
		self.fmm = func_monoid_monoid
		self.fmo = func_monoid_operator
		self.foo = func_operator_operator
		self.n = len(monoid_data)
		self.data = monoid_data * 2
		for i in range(self.n - 1, 0, -1):
			self.data[i] = self.fmm(self.data[2 * i], self.data[2 * i + 1])
		self.lazy = [self.oe] * (self.n * 2)

	def replace(self, index, value):
		index += self.n
		for shift in range(index.bit_length() - 1, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		self.data[index] = value
		self.lazy[index] = self.oe
		i = index
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def effect(self, l, r, operator):
		l += self.n
		r += self.n
		l0 = l
		r0 = r - 1
		while l0 % 2 == 0:
			l0 //= 2
		while r0 % 2 == 1:
			r0 //= 2
		for shift in range(l0.bit_length() - 1, 0, -1):
			i = l0 >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		for shift in range(r0.bit_length() - 1, 0, -1):
			i = r0 >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		while l < r:
			if l % 2:
				self.lazy[l] = self.foo(self.lazy[l], operator)
				l += 1
			if r % 2:
				r -= 1
				self.lazy[r] = self.foo(self.lazy[r], operator)
			l //= 2
			r //= 2
		i = l0
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe
		i = r0
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def all_folded(self):
		return self.data[1]

	def folded(self, l, r):
		l += self.n
		r += self.n
		l0 = l
		r0 = r - 1
		while l0 % 2 == 0:
			l0 //= 2
		while r0 % 2 == 1:
			r0 //= 2
		for shift in range(l0.bit_length() - 1, 0, -1):
			i = l0 >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		for shift in range(r0.bit_length() - 1, 0, -1):
			i = r0 >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		left_folded = self.me
		right_folded = self.me
		while l < r:
			if l % 2:
				left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
				l += 1
			if r % 2:
				r -= 1
				right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
			l //= 2
			r //= 2
		return self.fmm(left_folded, right_folded)
import sys
input = sys.stdin.buffer.readline
read = sys.stdin.buffer.read
MOD = 998244353
mask32 = (1 << 32) - 1
(N, Q) = map(int, input().split())
pw = [1]
for _ in range(N + 2):
	pw.append(pw[-1] * 10 % MOD)

def fmm(m1, m2):
	v1 = m1 >> 32
	l1 = m1 & mask32
	v2 = m2 >> 32
	l2 = m2 & mask32
	v = (v1 * pw[l2] + v2) % MOD
	l = l1 + l2
	return (v << 32) + l
inv9 = pow(9, MOD - 2, MOD)

def fmo(m, o):
	if o == -1:
		return m
	else:
		l = m & mask32
		v = o * (pw[l] - 1) * inv9 % MOD
		return (v << 32) + l

def foo(o1, o2):
	if o2 == -1:
		return o1
	else:
		return o2
lst = LazySegmentTree([(1 << 32) + 1] * N, 0, -1, fmm, fmo, foo)
LRDs = map(int, read().split())
for (L, R, D) in zip(LRDs, LRDs, LRDs):
	lst.effect(L - 1, R, D)
	print(lst.folded(0, N) >> 32)


import sys
input = sys.stdin.readline
(N, Q) = map(int, input().split())
LRD = [tuple(map(int, input().split())) for i in range(Q)]
MOD = 998244353

class LazySegTree:

	def __init__(self, op, e, mapping, composition, _id, arr=[]):
		self.op = op
		self.e = e
		self.mapping = mapping
		self.composition = composition
		self.id = _id
		self.n = len(arr)
		self.log = self._ceil_pow2(self.n)
		self.size = 1 << self.log
		self.d = [e()] * (2 * self.size)
		self.lz = [_id()] * self.size
		for i in range(self.n):
			self.d[self.size + i] = arr[i]
		for i in range(self.size - 1, 0, -1):
			self._update(i)

	def _ceil_pow2(self, n):
		assert n >= 0
		x = 0
		while 1 << x < n:
			x += 1
		return x

	def set(self, p, x):
		assert 0 <= p < self.n
		p += self.size
		for i in range(self.log, 0, -1):
			self._push(p >> i)
		self.d[p] = x
		for i in range(1, self.log + 1):
			self._update(p >> i)

	def get(self, p):
		assert 0 <= p < self.n
		p += self.size
		for i in range(self.log, 0, -1):
			self._push(p >> i)
		return self.d[p]

	def prod(self, l, r):
		assert 0 <= l <= r <= self.n
		if l == r:
			return self.e()
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self._push(l >> i)
			if r >> i << i != r:
				self._push(r >> i)
		sml = smr = self.e()
		while l < r:
			if l & 1:
				sml = self.op(sml, self.d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.d[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def all_prod(self):
		return self.d[1]

	def apply(self, p, f):
		assert 0 <= p < self.n
		p += self.size
		for i in range(self.log, 0, -1):
			self._push(p >> i)
		self.d[p] = self.mapping(f, self.d[p])
		for i in range(1, self.log + 1):
			self._update(p >> i)

	def apply_lr(self, l, r, f):
		assert 0 <= l <= r <= self.n
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self._push(l >> i)
			if r >> i << i != r:
				self._push(r - 1 >> i)
		(l2, r2) = (l, r)
		while l < r:
			if l & 1:
				self._all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self._all_apply(r, f)
			l >>= 1
			r >>= 1
		(l, r) = (l2, r2)
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self._update(l >> i)
			if r >> i << i != r:
				self._update(r - 1 >> i)

	def _update(self, k):
		self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])

	def _all_apply(self, k, f):
		self.d[k] = self.mapping(f, self.d[k])
		if k < self.size:
			self.lz[k] = self.composition(f, self.lz[k])

	def _push(self, k):
		self._all_apply(2 * k, self.lz[k])
		self._all_apply(2 * k + 1, self.lz[k])
		self.lz[k] = self.id()
inv9 = pow(9, MOD - 2, MOD)

def op(l, r):
	(lx, lw) = l
	(rx, rw) = r
	return ((lx * rw + rx) % MOD, lw * rw % MOD)

def e():
	return (0, 1)

def mapping(l, r):
	if l == 0:
		return r
	(rx, rw) = r
	return ((rw - 1) * inv9 * l % MOD, rw)

def composition(l, r):
	return r if l == 0 else l

def _id():
	return 0
segt = LazySegTree(op, e, mapping, composition, _id, [(1, 10) for i in range(N)])
ans = []
for (l, r, d) in LRD:
	l -= 1
	segt.apply_lr(l, r, d)
	ans.append(segt.all_prod()[0])
print(*ans, sep='\n')


import sys
input = sys.stdin.readline

class LazySegmentTree:

	def __init__(self, n, op, e, mapping, composition, id):
		self.n = n
		self.op = op
		self.e = e
		self.mapping = mapping
		self.composition = composition
		self.id = id
		self.log = (n - 1).bit_length()
		self.size = 1 << self.log
		self.d = [e] * (2 * self.size)
		self.lz = [id] * self.size

	def update(self, k):
		self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])

	def all_apply(self, k, f):
		self.d[k] = self.mapping(f, self.d[k])
		if k < self.size:
			self.lz[k] = self.composition(f, self.lz[k])

	def push(self, k):
		self.all_apply(2 * k, self.lz[k])
		self.all_apply(2 * k + 1, self.lz[k])
		self.lz[k] = self.id

	def build(self, arr):
		for (i, a) in enumerate(arr):
			self.d[self.size + i] = a
		for i in range(1, self.size)[::-1]:
			self.update(i)

	def set(self, p, x):
		p += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(p >> i)
		self.d[p] = x
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def get(self, p):
		p += self.size
		for i in range(1, self.log + 1):
			self.push(p >> i)
		return self.d[p]

	def prod(self, l, r):
		if l == r:
			return self.e
		l += self.size
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r >> i)
		sml = smr = self.e
		while l < r:
			if l & 1:
				sml = self.op(sml, self.d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.d[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def all_prod(self):
		return self.d[1]

	def apply(self, p, f):
		p += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(p >> i)
		self.d[p] = self.mapping(f, self.d[p])
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def range_apply(self, l, r, f):
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r - 1 >> i)
		l2 = l
		r2 = r
		while l < r:
			if l & 1:
				self.all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.all_apply(r, f)
			l >>= 1
			r >>= 1
		l = l2
		r = r2
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.update(l >> i)
			if r >> i << i != r:
				self.update(r - 1 >> i)

	def max_right(self, l, g):
		if l == self.n:
			return self.n
		l += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(l >> i)
		sm = self.e
		while True:
			while l % 2 == 0:
				l >>= 1
			if not g(self.op(sm, self.d[l])):
				while l < self.size:
					self.push(l)
					l = 2 * l
					if g(self.op(sm, self.d[l])):
						sm = self.op(sm, self.d[l])
						l += 1
				return l - self.size
			sm = self.op(sm, self.d[l])
			l += 1
			if l & -l == l:
				return self.n

	def min_left(self, r, g):
		if r == 0:
			return 0
		r += self.size
		for i in range(1, self.log + 1)[::-1]:
			self.push(r - 1 >> i)
		sm = self.e
		while True:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(self.op(self.d[r], sm)):
				while r < self.size:
					self.push(r)
					r = 2 * r + 1
					if g(self.op(self.d[r], sm)):
						sm = self.op(self.d[r], sm)
						r -= 1
				return r + 1 - self.size
			sm = self.op(self.d[r], sm)
			if r & -r == r:
				return 0
mod = 998244353
(N, Q) = map(int, input().split())
O = [1] * (N + 1)
P = [1] * (N + 1)
c = kk = 1
for i in range(1, N + 1):
	O[i] = c
	kk = kk * 10 % mod
	P[i] = kk
	c = (c + kk) % mod

def op(x, y):
	return ((P[y[1]] * x[0] + y[0]) % mod, x[1] + y[1])

def mapping(p, x):
	if p:
		return (O[x[1]] * p % mod, x[1])
	return x

def composition(p, q):
	if p == 0:
		return q
	return p
res = [(1, 1)] * N
LST = LazySegmentTree(N, op, (0, 0), mapping, composition, 0)
LST.build(res)
for _ in range(Q):
	(l, r, D) = map(int, input().split())
	LST.range_apply(l - 1, r, D)
	print(LST.all_prod()[0])


import sys
input = sys.stdin.readline
(N, Q) = map(int, input().split())
mod = 998244353

class lazy_segtree:

	def __init__(s, op, e, mapping, composition, id, v):
		if type(v) is int:
			v = [e()] * v
		s._n = len(v)
		s.log = s.ceil_pow2(s._n)
		s.size = 1 << s.log
		s.d = [e()] * (2 * s.size)
		s.lz = [id()] * s.size
		s.e = e
		s.op = op
		s.mapping = mapping
		s.composition = composition
		s.id = id
		for i in range(s._n):
			s.d[s.size + i] = v[i]
		for i in range(s.size - 1, 0, -1):
			s.update(i)

	def set(s, p, x):
		p += s.size
		for i in range(s.log, 0, -1):
			s.push(p >> i)
		s.d[p] = x
		for i in range(1, s.log + 1):
			s.update(p >> i)

	def get(s, p):
		p += s.size
		for i in range(s.log, 0, -1):
			s.push(p >> i)
		return s.d[p]

	def prod(s, l, r):
		if l == r:
			return s.e()
		l += s.size
		r += s.size
		for i in range(s.log, 0, -1):
			if l >> i << i != l:
				s.push(l >> i)
			if r >> i << i != r:
				s.push(r >> i)
		(sml, smr) = (s.e(), s.e())
		while l < r:
			if l & 1:
				sml = s.op(sml, s.d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = s.op(s.d[r], smr)
			l >>= 1
			r >>= 1
		return s.op(sml, smr)

	def all_prod(s):
		return s.d[1]

	def apply(s, p, f):
		p += s.size
		for i in range(s.log, 0, -1):
			s.push(p >> i)
		s.d[p] = s.mapping(f, s.d[p])
		for i in range(1, s.log + 1):
			s.update(p >> i)

	def apply(s, l, r, f):
		if l == r:
			return
		l += s.size
		r += s.size
		for i in range(s.log, 0, -1):
			if l >> i << i != l:
				s.push(l >> i)
			if r >> i << i != r:
				s.push(r - 1 >> i)
		(l2, r2) = (l, r)
		while l < r:
			if l & 1:
				sml = s.all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				smr = s.all_apply(r, f)
			l >>= 1
			r >>= 1
		(l, r) = (l2, r2)
		for i in range(1, s.log + 1):
			if l >> i << i != l:
				s.update(l >> i)
			if r >> i << i != r:
				s.update(r - 1 >> i)

	def max_right(s, l, g):
		if l == s._n:
			return _n
		l += s.size
		for i in range(s.log, 0, -1):
			s.push(l >> i)
		sm = s.e()
		while True:
			while l % 2 == 0:
				l >>= 1
			if not g(s.op(sm, s.d[l])):
				while l < s.size:
					s.push(l)
					l = 2 * l
					if g(s.op(sm, s.d[l])):
						sm = s.op(sm, s.d[l])
						l += 1
				return l - s.size
			sm = s.op(sm, s.d[l])
			l += 1
			if l & -l == l:
				break
		return s._n

	def min_left(s, r, g):
		if r == 0:
			return 0
		r += s.size
		for i in range(s.log, 0, -1):
			s.push(r - 1 >> i)
		sm = s.e()
		while True:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(s.op(s.d[r], sm)):
				while r < s.size:
					s.push(r)
					r = 2 * r + 1
					if g(s.op(s.d[r], sm)):
						sm = s.op(s.d[r], sm)
						r -= 1
				return r + 1 - s.size
			sm = s.op(s.d[r], sm)
			if r & -r == r:
				break
		return 0

	def update(s, k):
		s.d[k] = s.op(s.d[2 * k], s.d[2 * k + 1])

	def all_apply(s, k, f):
		s.d[k] = s.mapping(f, s.d[k])
		if k < s.size:
			s.lz[k] = s.composition(f, s.lz[k])

	def push(s, k):
		s.all_apply(2 * k, s.lz[k])
		s.all_apply(2 * k + 1, s.lz[k])
		s.lz[k] = s.id()

	def ceil_pow2(s, n):
		x = 0
		while 1 << x < n:
			x += 1
		return x
inf = 10 ** 18

def e():
	return 0

def op(x, y):
	(x0, x1) = (x >> 32, x % (1 << 32))
	(y0, y1) = (y >> 32, y % (1 << 32))
	return ((x0 + y0) % mod << 32) + (x1 + y1) % mod

def mapping(f, x):
	(x0, x1) = (x >> 32, x % (1 << 32))
	if f != inf:
		return (f * x1 % mod << 32) + x1
	else:
		return x

def composition(f, g):
	if f != inf:
		return f
	else:
		return g

def id(x=inf):
	return x
a = [pow(10, N - i - 1, mod) for i in range(N)]
seg = lazy_segtree(op, e, mapping, composition, id, [(x << 32) + x for x in a])
for _ in range(Q):
	(l, r, d) = map(int, input().split())
	l -= 1
	seg.apply(l, r, d)
	print(seg.all_prod() >> 32)


class LazySegmentTree:

	def __init__(self, array, f, g, h, ti, ei):
		self.f = f
		self.g = g
		self.h = h
		self.ti = ti
		self.ei = ei
		self.height = height = len(array).bit_length()
		self.n = n = 2 ** height
		self.dat = dat = [ti] * n + array + [ti] * (n - len(array))
		self.laz = [ei] * (2 * n)
		for i in range(n - 1, 0, -1):
			dat[i] = f(dat[i << 1], dat[i << 1 | 1])

	def reflect(self, k):
		dat = self.dat
		ei = self.ei
		laz = self.laz
		g = self.g
		return self.dat[k] if laz[k] is ei else g(dat[k], laz[k])

	def evaluate(self, k):
		laz = self.laz
		ei = self.ei
		reflect = self.reflect
		dat = self.dat
		h = self.h
		if laz[k] is ei:
			return
		laz[k << 1 | 0] = h(laz[k << 1 | 0], laz[k])
		laz[k << 1 | 1] = h(laz[k << 1 | 1], laz[k])
		dat[k] = reflect(k)
		laz[k] = ei

	def thrust(self, k):
		height = self.height
		evaluate = self.evaluate
		for i in range(height, 0, -1):
			evaluate(k >> i)

	def recalc(self, k):
		dat = self.dat
		reflect = self.reflect
		f = self.f
		while k:
			k >>= 1
			dat[k] = f(reflect(k << 1 | 0), reflect(k << 1 | 1))

	def update(self, a, b, x):
		thrust = self.thrust
		n = self.n
		h = self.h
		laz = self.laz
		recalc = self.recalc
		a += n
		b += n - 1
		l = a
		r = b + 1
		thrust(a)
		thrust(b)
		while l < r:
			if l & 1:
				laz[l] = h(laz[l], x)
				l += 1
			if r & 1:
				r -= 1
				laz[r] = h(laz[r], x)
			l >>= 1
			r >>= 1
		recalc(a)
		recalc(b)

	def set_val(self, a, x):
		n = self.n
		thrust = self.thrust
		dat = self.dat
		laz = self.laz
		recalc = self.recalc
		ei = self.ei
		a += n
		thrust(a)
		dat[a] = x
		laz[a] = ei
		recalc(a)

	def query(self, a, b):
		f = self.f
		ti = self.ti
		n = self.n
		thrust = self.thrust
		reflect = self.reflect
		a += n
		b += n - 1
		thrust(a)
		thrust(b)
		l = a
		r = b + 1
		vl = vr = ti
		while l < r:
			if l & 1:
				vl = f(vl, reflect(l))
				l += 1
			if r & 1:
				r -= 1
				vr = f(reflect(r), vr)
			l >>= 1
			r >>= 1
		return f(vl, vr)

def pow_k(x, n, p=10 ** 9 + 7):
	if n == 0:
		return 1
	K = 1
	while n > 1:
		if n % 2 != 0:
			K = K * x % p
		x = x * x % p
		n //= 2
	return K * x % p
mod = 998244353

def f(a, b):
	(an, ah) = a
	(bn, bh) = b
	return ((an * tenmod[bh] + bn) % mod, ah + bh)

def g(a, b):
	(an, ah) = a
	return ((tenmod[ah] - 1) * 443664157 % mod * b, ah)
h = lambda a, b: b
ti = (0, 0)
ei = 0
import sys
input = sys.stdin.readline
MI = lambda : map(int, input().split())
(N, Q) = MI()
tenmod = [pow_k(10, i, mod) for i in range(N + 1)]
lst = LazySegmentTree([(1, 1)] * N, f=f, g=g, h=h, ti=ti, ei=ei)
for _ in [0] * Q:
	(l, r, d) = MI()
	lst.update(l - 1, r, d)
	print(lst.query(0, N)[0])


import sys
input = sys.stdin.buffer.readline

class LazySegmentTree:

	def __init__(self, n, unitX, unitA, X_f, A_f, XA_map):
		self.n = n
		self.unitX = unitX
		self.unitA = unitA
		self.X_f = X_f
		self.A_f = A_f
		self.XA_map = XA_map
		self.X = [unitX] * (self.n + self.n)
		self.A = [unitA] * (self.n + self.n)

	def __getitem__(self, i):
		i += self.n
		self._propagate_above(i)
		return self.X[i]

	def __setitem__(self, i, x):
		i += self.n
		self._propagate_above(i)
		self.X[i] = x
		self._calc_above(i)

	def build(self, array):
		for (i, val) in enumerate(array, self.n):
			self.X[i] = val
		for i in range(self.n - 1, 0, -1):
			self.X[i] = self.X_f(self.X[i << 1], self.X[i << 1 | 1])

	def _calc_above(self, i):
		while i > 1:
			i >>= 1
			self.X[i] = self.X_f(self.X[i << 1], self.X[i << 1 | 1])

	def _propagate_above(self, i):
		k = i >> 1
		H = k.bit_length() - 1
		for h in range(H, -1, -1):
			i = k >> h
			if self.A[i] == self.unitA:
				continue
			self.X[i << 1] = self.XA_map(self.X[i << 1], self.A[i])
			self.X[i << 1 | 1] = self.XA_map(self.X[i << 1 | 1], self.A[i])
			self.A[i << 1] = self.A_f(self.A[i << 1], self.A[i])
			self.A[i << 1 | 1] = self.A_f(self.A[i << 1 | 1], self.A[i])
			self.A[i] = self.unitA

	def fold(self, l, r):
		l += self.n
		r += self.n
		(l0, r0) = (l // (l & -l), r // (r & -r) - 1)
		self._propagate_above(l0)
		self._propagate_above(r0)
		xl = self.unitX
		xr = self.unitX
		while l < r:
			if l & 1:
				xl = self.X_f(xl, self.X[l])
				l += 1
			if r & 1:
				r -= 1
				xr = self.X_f(self.X[r], xr)
			l >>= 1
			r >>= 1
		return self.X_f(xl, xr)

	def apply(self, i, a):
		i += self.n
		self._propagate_above(i)
		self.X[i] = self.XA_map(self.X[i], a)
		self.A[i] = self.A_f(self.A[i], a)
		self._calc_above(i)

	def apply_range(self, l, r, a):
		l += self.n
		r += self.n
		(l0, r0) = (l // (l & -l), r // (r & -r) - 1)
		self._propagate_above(l0)
		self._propagate_above(r0)
		while l < r:
			if l & 1:
				self.X[l] = self.XA_map(self.X[l], a)
				self.A[l] = self.A_f(self.A[l], a)
				l += 1
			if r & 1:
				r -= 1
				self.X[r] = self.XA_map(self.X[r], a)
				self.A[r] = self.A_f(self.A[r], a)
			l >>= 1
			r >>= 1
		self._calc_above(l0)
		self._calc_above(r0)
(n, q) = map(int, input().split())
queries = [list(map(int, input().split())) for i in range(q)]
MOD = 998244353
pow_ = [1] * (n + 1)
for i in range(n):
	pow_[i + 1] = pow_[i] * 10 % MOD
digit = [[0] * (n + 1) for i in range(10)]
for i in range(n):
	for val in range(10):
		digit[val][i + 1] = (digit[val][i] + pow_[i] * val) % MOD
unitX = (0, 0)

def X_f(x1, x2):
	return ((x1[0] * pow_[x2[1]] + x2[0]) % MOD, x1[1] + x2[1])
unitA = -1
A_f = lambda a1, a2: a1 if a2 == unitA else a2

def XA_map(x, a):
	if a != unitA:
		x = (digit[a][x[1]], x[1])
	return x
lst = LazySegmentTree(n, unitX, unitA, X_f, A_f, XA_map)
lst.build([(1, 1) for i in range(n)])
ans = []
for (l, r, d) in queries:
	l -= 1
	lst.apply_range(l, r, d)
	ans.append(lst.fold(0, n)[0])
print(*ans, sep='\n')


import sys
sysread = sys.stdin.buffer.readline
read = sys.stdin.buffer.read
printout = sys.stdout.write
sprint = sys.stdout.flush
sys.setrecursionlimit(10 ** 7)
import math
INF = 1 << 50
EPS = 1e-08
mod = 998244353

def intread():
	return int(sysread())

def mapline(t=int):
	return map(t, sysread().split())

def mapread(t=int):
	return map(t, read().split())

class lazy_segtree:

	def __init__(self, n, mod, init=0, init_val=None):
		self.n = n
		self.init = init
		self.k = math.ceil(math.log2(n))
		self.add_val = 1 << self.k
		self.lazy = [INF] * (1 << self.k + 1)
		self.bins = [self.init] * (1 << self.k + 1)
		if init_val != None:
			self.update_set(init_val)
		self.mod = mod
		self.build()
		self.bases = self.bins.copy()

	def __getitem__(self, idx):
		return self.bins[idx]

	def __setitem__(self, idx, val):
		self.bins[idx] = val

	def update_set(self, vals):
		for (idx, i) in enumerate(range(self.add_val, self.add_val * 2)):
			if len(vals) > idx:
				self[i] = vals[idx]
			else:
				continue

	def _func(self, k):

		def f(x):
			return k
		return f

	def fx(self, l, r):
		return (l + r) % self.mod

	def build(self):
		for i in range(self.add_val - 1, 0, -1):
			self[i] = self.fx(self[2 * i], self[2 * i + 1])

	def eval(self, idx):
		if self.lazy[idx] == INF:
			return
		if idx < self.add_val:
			self.lazy[idx * 2 + 1] = self.lazy[idx]
			self.lazy[idx * 2] = self.lazy[idx]
		self[idx] = self.lazy[idx] * self.bases[idx]
		self.lazy[idx] = INF

	def update(self, a, b, x):
		self._update(a, b, x, 1, 0, self.add_val)

	def _update(self, a, b, x, k, l, r):
		self.eval(k)
		if a <= l and b >= r:
			self.lazy[k] = self._func(x)(self.lazy[k])
			self.eval(k)
		elif a < r and l < b:
			self._update(a, b, x, 2 * k, l, (l + r) // 2)
			self._update(a, b, x, 2 * k + 1, (l + r) // 2, r)
			self[k] = self.fx(self[2 * k], self[2 * k + 1])

	def query(self, a, b):
		return self.query_sub(a, b, 1, 0, self.add_val)

	def query_sub(self, a, b, k, l, r):
		self.eval(k)
		if r <= a or b <= l:
			return INF
		elif a <= l and b >= r:
			return self[k]
		else:
			vl = self.query_sub(a, b, k * 2, l, (l + r) // 2)
			vr = self.query_sub(a, b, k * 2 + 1, (l + r) // 2, r)
			return self.fx(vl, vr)

def get_powmod(x, k, mod):
	ret = [1]
	v = 1
	for i in range(k):
		v *= x
		v %= mod
		ret.append(v)
	return ret

def run():
	(N, Q) = mapline()
	A = get_powmod(10, N - 1, mod)[::-1]
	lst = lazy_segtree(N, mod, init_val=A)
	for _ in range(Q):
		(l, r, d) = mapline()
		l -= 1
		r -= 1
		lst.update(l, r + 1, d)
		print(lst[1])
run()


import sys
input = lambda : sys.stdin.readline().rstrip()

class SegmentTree:

	def __init__(self, init, unitX, unitA, f, g, h):
		self.f = f
		self.g = g
		self.h = h
		self.unitX = unitX
		self.unitA = unitA
		self.f = f
		if type(init) == int:
			self.n = init
			self.X = [unitX] * (self.n * 2)
			self.size = [1] * (self.n * 2)
		else:
			self.n = len(init)
			self.X = [unitX] * self.n + init + [unitX] * (self.n - len(init))
			self.size = [0] * self.n + [1] * len(init) + [0] * (self.n - len(init))
			for i in range(self.n - 1, 0, -1):
				self.X[i] = self.f(self.X[i * 2], self.X[i * 2 | 1])
		for i in range(self.n - 1, 0, -1):
			self.size[i] = self.size[i * 2] + self.size[i * 2 | 1]
		self.A = [unitA] * (self.n * 2)

	def update(self, i, x):
		i += self.n
		self.propagate_above(i)
		self.X[i] = x
		self.A[i] = unitA
		self.calc_above(i)

	def calc(self, i):
		return self.g(self.X[i], self.A[i], self.size[i])

	def calc_above(self, i):
		i >>= 1
		while i:
			self.X[i] = self.f(self.calc(i * 2), self.calc(i * 2 | 1))
			i >>= 1

	def propagate(self, i):
		self.X[i] = self.g(self.X[i], self.A[i], self.size[i])
		self.A[i * 2] = self.h(self.A[i * 2], self.A[i])
		self.A[i * 2 | 1] = self.h(self.A[i * 2 | 1], self.A[i])
		self.A[i] = self.unitA

	def propagate_above(self, i):
		H = i.bit_length()
		for h in range(H, 0, -1):
			self.propagate(i >> h)

	def propagate_all(self):
		for i in range(1, self.n):
			self.propagate(i)

	def getrange(self, l, r):
		l += self.n
		r += self.n
		(l0, r0) = (l // (l & -l), r // (r & -r) - 1)
		self.propagate_above(l0)
		self.propagate_above(r0)
		al = self.unitX
		ar = self.unitX
		while l < r:
			if l & 1:
				al = self.f(al, self.calc(l))
				l += 1
			if r & 1:
				r -= 1
				ar = self.f(self.calc(r), ar)
			l >>= 1
			r >>= 1
		return self.f(al, ar)

	def getvalue(self, i):
		i += self.n
		self.propagate_above(i)
		return self.calc(i)

	def operate_range(self, l, r, a):
		l += self.n
		r += self.n
		(l0, r0) = (l // (l & -l), r // (r & -r) - 1)
		self.propagate_above(l0)
		self.propagate_above(r0)
		while l < r:
			if l & 1:
				self.A[l] = self.h(self.A[l], a)
				l += 1
			if r & 1:
				r -= 1
				self.A[r] = self.h(self.A[r], a)
			l >>= 1
			r >>= 1
		self.calc_above(l0)
		self.calc_above(r0)

	def check(self, randX, randA, maxs, rep):
		from random import randrange
		for _ in range(rep):
			x = randX()
			y = randX()
			z = randX()
			a = randA()
			b = randA()
			c = randA()
			s = randrange(1, maxs + 1)
			t = randrange(1, maxs + 1)
			err = 0
			if not f(x, unitX) == f(unitX, x) == x:
				err = 1
				print('!!!!! unitX Error !!!!!')
				print('unitX =', unitX)
				print('x =', x)
				print('f(x, unitX) =', f(x, unitX))
				print('f(unitX, x) =', f(unitX, x))
			if not h(a, unitA) == h(unitA, a) == a:
				err = 1
				print('!!!!! unitA Error !!!!!')
				print('unitA =', unitA)
				print('a =', a)
				print('f(a, unitA) =', f(a, unitA))
				print('f(unitA, a) =', f(unitA, a))
			if not f(f(x, y), z) == f(x, f(y, z)):
				err = 1
				print('!!!!! Associativity Error X !!!!!')
				print('x, y, z, f(x, y), f(y, x) =', x, y, z, f(x, y), f(y, x))
				print('f(f(x, y), z) =', f(f(x, y), z))
				print('f(x, f(y, z)) =', f(x, f(y, z)))
			if not h(h(a, b), c) == h(a, h(b, c)):
				err = 1
				print('!!!!! Associativity Error A !!!!!')
				print('a, b, c, h(a, b), h(b, c) =', a, b, c, h(a, b), h(b, c))
				print('h(h(a, b), c) =', h(h(a, b), c))
				print('h(a, h(b, c)) =', h(a, h(b, c)))
			if not g(x, unitA, s) == x:
				err = 1
				print('!!!!! Identity Error !!!!!')
				print('unitA, x, s =', unitA, x, s)
				print('g(x, unitA, s) =', g(x, unitA, s))
			if not g(g(x, a, s), b, s) == g(x, h(a, b), s):
				err = 1
				print('!!!!! Act Error 1 !!!!!')
				print('x, a, b, s, g(x, a, s), h(a, b) =', x, a, b, s, g(x, a, s), h(a, b))
				print('g(g(x, a, s), b, s) =', g(g(x, a, s), b, s))
				print('g(x, h(a, b), s)    =', g(x, h(a, b), s))
			if not g(f(x, y), a, s + t) == f(g(x, a, s), g(y, a, t)):
				err = 1
				print('!!!!! Act Error 2 !!!!!')
				print('x, y, a, s, t, f(x, y), g(x, a, s), g(y, a, t) =', x, y, a, s, t, f(x, y), g(x, a, s), g(y, a, t))
				print('g(f(x, y), a, s + t)      =', g(f(x, y), a, s + t))
				print('f(g(x, a, s), g(y, a, t)) =', f(g(x, a, s), g(y, a, t)))
			if err:
				break
				assert f(x, unitX) == f(unitX, x) == x
				assert h(a, unitA) == h(unitA, a) == a
				assert f(f(x, y), z) == f(x, f(y, z))
				assert h(h(a, b), c) == h(a, h(b, c))
				assert g(x, unitA, s) == x
				assert g(g(x, a, s), b, s) == g(x, h(a, b), s)
				assert g(f(x, y), a, s + t) == f(g(x, a, s), g(y, a, t))
		else:
			pass
			print('Monoid Check OK!')

	def debug1(self):
		print('self.n =', self.n)
		deX = []
		deA = []
		deS = []
		(a, b) = (self.n, self.n * 2)
		while b:
			deX.append(self.X[a:b])
			deA.append(self.A[a:b])
			deS.append(self.size[a:b])
			(a, b) = (a // 2, a)
		print('--- debug ---')
		for d in deX[::-1]:
			print(d)
		print('--- ---')
		for d in deA[::-1]:
			print(d)
		print('--- ---')
		for d in deS[::-1]:
			print(d)
		print('--- ---')

	def debug(self, k=10):
		print('--- debug ---')
		print('point')
		for i in range(min(self.n - 1, k)):
			print(i, self.getvalue(i))
		print('prod')
		for i in range(min(self.n, k)):
			print(i, self.getrange(0, i))
		print('--- ---')
P = 998244353
inv9 = 443664157
mm = (1 << 18) - 1

def f(x, y):
	(l1, su1) = (x & mm, x >> 18)
	(l2, su2) = (y & mm, y >> 18)
	return ((su1 + su2) % P << 18) + l1

def g(x, a, s):
	(l, su) = (x & mm, x >> 18)
	return ((po10[s] - 1) * inv9 % P * po10[l] * a % P << 18) + l if a else x
h = lambda a, b: b if b else a
unitX = 0
unitA = 0
(N, Q) = map(int, input().split())
x = 1
X = []
po10 = []
for i in range(N):
	X.append((x << 18) + i)
	po10.append(x)
	x = x * 10 % P
po10.append(x)
st = SegmentTree(X, unitX, unitA, f, g, h)
if False:
	from random import randrange
	randX = lambda : (randrange(-10, 11), randrange(-10, 11))
	randA = lambda : ['', 'A', 'B'][randrange(3)]
	maxs = 10
	rep = 1000
	st.check(randX, randA, maxs, rep)
for _ in range(Q):
	(l, r, d) = map(int, input().split())
	(l, r) = (N - r, N - l + 1)
	st.operate_range(l, r, d)
	print(st.X[1] >> 18)


import sys
sys.setrecursionlimit(10 ** 6)
INF = 10 ** 9 + 1
MOD = 998244353

def set_depth(depth):
	global DEPTH, SEGTREE_SIZE, NONLEAF_SIZE
	DEPTH = depth
	SEGTREE_SIZE = 1 << DEPTH
	NONLEAF_SIZE = 1 << DEPTH - 1

def set_width(width):
	set_depth((width - 1).bit_length() + 1)

def get_size(pos):
	ret = pos.bit_length()
	return 1 << DEPTH - ret

def up(pos):
	pos += SEGTREE_SIZE // 2
	return pos // (pos & -pos)

def up_propagate(table, pos, binop):
	while pos > 1:
		pos >>= 1
		size = get_size(pos) // 2
		table[pos] = binop(table[pos * 2], table[pos * 2 + 1], size)

def full_up(table, binop):
	for pos in range(NONLEAF_SIZE - 1, 0, -1):
		size = get_size(pos) // 2
		table[pos] = binop(table[2 * pos], table[2 * pos + 1], size)

def force_down_propagate(action_table, value_table, pos, action_composite, action_force, action_unity):
	max_level = pos.bit_length() - 1
	size = NONLEAF_SIZE
	for level in range(max_level):
		size //= 2
		i = pos >> max_level - level
		action = action_table[i]
		if action != action_unity:
			action_table[i * 2] = action_composite(action, action_table[i * 2])
			action_table[i * 2 + 1] = action_composite(action, action_table[i * 2 + 1])
			action_table[i] = action_unity
			value_table[i * 2] = action_force(action, value_table[i * 2], size)
			value_table[i * 2 + 1] = action_force(action, value_table[i * 2 + 1], size)

def force_range_update(value_table, action_table, left, right, action, action_force, action_composite, action_unity):
	left += NONLEAF_SIZE
	right += NONLEAF_SIZE
	while left < right:
		if left & 1:
			value_table[left] = action_force(action, value_table[left], get_size(left))
			action_table[left] = action_composite(action, action_table[left])
			left += 1
		if right & 1:
			right -= 1
			value_table[right] = action_force(action, value_table[right], get_size(right))
			action_table[right] = action_composite(action, action_table[right])
		left //= 2
		right //= 2

def range_reduce(table, left, right, binop, unity):
	ret_left = unity
	ret_right = unity
	left += NONLEAF_SIZE
	right += NONLEAF_SIZE
	right_size = 0
	while left < right:
		if left & 1:
			size = get_size(left)
			ret_left = binop(ret_left, table[left], size)
			left += 1
		if right & 1:
			right -= 1
			ret_right = binop(table[right], ret_right, right_size)
			right_size += get_size(right)
		left //= 2
		right //= 2
	return binop(ret_left, ret_right, right_size)

def lazy_range_update(action_table, value_table, start, end, action, action_composite, action_force, action_unity, value_binop):
	L = up(start)
	R = up(end)
	force_down_propagate(action_table, value_table, L, action_composite, action_force, action_unity)
	force_down_propagate(action_table, value_table, R, action_composite, action_force, action_unity)
	force_range_update(value_table, action_table, start, end, action, action_force, action_composite, action_unity)
	up_propagate(value_table, L, value_binop)
	up_propagate(value_table, R, value_binop)

def lazy_range_reduce(action_table, value_table, start, end, action_composite, action_force, action_unity, value_binop, value_unity):
	force_down_propagate(action_table, value_table, up(start), action_composite, action_force, action_unity)
	force_down_propagate(action_table, value_table, up(end), action_composite, action_force, action_unity)
	return range_reduce(value_table, start, end, value_binop, value_unity)

def debug(*x):
	print(*x, file=sys.stderr)

def main():
	(N, Q) = map(int, input().split())
	set_width(N + 1)
	value_unity = 0
	value_table = [value_unity] * SEGTREE_SIZE
	value_table[NONLEAF_SIZE:NONLEAF_SIZE + N] = [1] * N
	action_unity = None
	action_table = [action_unity] * SEGTREE_SIZE
	cache11 = {}
	i = 1
	p = 1
	step = 10
	while i <= N:
		cache11[i] = p
		p = (p * step + p) % MOD
		step = step * step % MOD
		i *= 2
	cache10 = {0: 1}
	i = 1
	p = 10
	while i <= N:
		cache10[i] = p
		p = p * 10 % MOD
		i += 1

	def action_force(action, value, size):
		if action == action_unity:
			return value
		return cache11[size] * action % MOD

	def action_composite(new_action, old_action):
		if new_action == action_unity:
			return old_action
		return new_action

	def value_binop(a, b, size):
		return (a * cache10[size] + b) % MOD
	full_up(value_table, value_binop)
	ret = lazy_range_reduce(action_table, value_table, 0, N, action_composite, action_force, action_unity, value_binop, value_unity)
	for _q in range(Q):
		(l, r, d) = map(int, input().split())
		lazy_range_update(action_table, value_table, l - 1, r, d, action_composite, action_force, action_unity, value_binop)
		ret = lazy_range_reduce(action_table, value_table, 0, N, action_composite, action_force, action_unity, value_binop, value_unity)
		print(ret)
T1 = '\n8 5\n3 6 2\n1 4 7\n3 8 3\n2 2 2\n4 5 1\n'
TEST_T1 = '\n>>> as_input(T1)\n>>> main()\n11222211\n77772211\n77333333\n72333333\n72311333\n'
T2 = '\n200000 1\n123 456 7\n'
TEST_T2 = '\n>>> as_input(T2)\n>>> main()\n641437905\n'
T3 = '\n4 4\n1 1 2\n1 2 3\n1 3 4\n1 4 5\n'
TEST_T3 = '\n>>> as_input(T3)\n>>> main()\n2111\n3311\n4441\n5555\n'
T4 = '\n4 4\n4 4 2\n3 4 3\n2 4 4\n1 4 5\n1112\n1133\n1444\n5555\n'
TEST_T4 = '\n>>> as_input(T4)\n>>> main()\n1112\n1133\n1444\n5555\n'
T5 = '\n9 3\n1 9 1\n1 9 5\n1 9 9\n'
TEST_T5 = '\n>>> as_input(T5)\n>>> main()\n111111111\n555555555\n1755646\n'

def _test():
	import doctest
	doctest.testmod()
	g = globals()
	for k in sorted(g):
		if k.startswith('TEST_'):
			doctest.run_docstring_examples(g[k], g, name=k)

def as_input(s):
	import io
	f = io.StringIO(s.strip())
	g = globals()
	g['input'] = lambda : bytes(f.readline(), 'ascii')
	g['read'] = lambda : bytes(f.read(), 'ascii')
input = sys.stdin.buffer.readline
read = sys.stdin.buffer.read
if sys.argv[-1] == '-t':
	print('testing')
	_test()
	sys.exit()
main()


import typing

class LazySegTree:

	def __init__(self, op: typing.Callable[[typing.Any, typing.Any], typing.Any], e: typing.Any, mapping: typing.Callable[[typing.Any, typing.Any], typing.Any], composition: typing.Callable[[typing.Any, typing.Any], typing.Any], id_: typing.Any, v: typing.Union[int, typing.List[typing.Any]]) -> None:
		self._op = op
		self._e = e
		self._mapping = mapping
		self._composition = composition
		self._id = id_
		if isinstance(v, int):
			v = [e] * v
		self._n = len(v)
		self._log = self._ceil_pow2(self._n)
		self._size = 1 << self._log
		self._d = [e] * (2 * self._size)
		self._lz = [self._id] * self._size
		for i in range(self._n):
			self._d[self._size + i] = v[i]
		for i in range(self._size - 1, 0, -1):
			self._update(i)

	def set(self, p: int, x: typing.Any) -> None:
		assert 0 <= p < self._n
		p += self._size
		for i in range(self._log, 0, -1):
			self._push(p >> i)
		self._d[p] = x
		for i in range(1, self._log + 1):
			self._update(p >> i)

	def get(self, p: int) -> typing.Any:
		assert 0 <= p < self._n
		p += self._size
		for i in range(self._log, 0, -1):
			self._push(p >> i)
		return self._d[p]

	def prod(self, left: int, right: int) -> typing.Any:
		assert 0 <= left <= right <= self._n
		if left == right:
			return self._e
		left += self._size
		right += self._size
		for i in range(self._log, 0, -1):
			if left >> i << i != left:
				self._push(left >> i)
			if right >> i << i != right:
				self._push(right >> i)
		sml = self._e
		smr = self._e
		while left < right:
			if left & 1:
				sml = self._op(sml, self._d[left])
				left += 1
			if right & 1:
				right -= 1
				smr = self._op(self._d[right], smr)
			left >>= 1
			right >>= 1
		return self._op(sml, smr)

	def all_prod(self) -> typing.Any:
		return self._d[1]

	def apply(self, left: int, right: typing.Optional[int]=None, f: typing.Optional[typing.Any]=None):
		assert f is not None
		if right is None:
			p = left
			assert 0 <= left < self._n
			p += self._size
			for i in range(self._log, 0, -1):
				self._push(p >> i)
			self._d[p] = self._mapping(f, self._d[p])
			for i in range(1, self._log + 1):
				self._update(p >> i)
		else:
			assert 0 <= left <= right <= self._n
			if left == right:
				return
			left += self._size
			right += self._size
			for i in range(self._log, 0, -1):
				if left >> i << i != left:
					self._push(left >> i)
				if right >> i << i != right:
					self._push(right - 1 >> i)
			l2 = left
			r2 = right
			while left < right:
				if left & 1:
					self._all_apply(left, f)
					left += 1
				if right & 1:
					right -= 1
					self._all_apply(right, f)
				left >>= 1
				right >>= 1
			left = l2
			right = r2
			for i in range(1, self._log + 1):
				if left >> i << i != left:
					self._update(left >> i)
				if right >> i << i != right:
					self._update(right - 1 >> i)

	def max_right(self, left: int, g: typing.Callable[[typing.Any], bool]) -> int:
		assert 0 <= left <= self._n
		assert g(self._e)
		if left == self._n:
			return self._n
		left += self._size
		for i in range(self._log, 0, -1):
			self._push(left >> i)
		sm = self._e
		first = True
		while first or left & -left != left:
			first = False
			while left % 2 == 0:
				left >>= 1
			if not g(self._op(sm, self._d[left])):
				while left < self._size:
					self._push(left)
					left *= 2
					if g(self._op(sm, self._d[left])):
						sm = self._op(sm, self._d[left])
						left += 1
				return left - self._size
			sm = self._op(sm, self._d[left])
			left += 1
		return self._n

	def min_left(self, right: int, g: typing.Any) -> int:
		assert 0 <= right <= self._n
		assert g(self._e)
		if right == 0:
			return 0
		right += self._size
		for i in range(self._log, 0, -1):
			self._push(right - 1 >> i)
		sm = self._e
		first = True
		while first or right & -right != right:
			first = False
			right -= 1
			while right > 1 and right % 2:
				right >>= 1
			if not g(self._op(self._d[right], sm)):
				while right < self._size:
					self._push(right)
					right = 2 * right + 1
					if g(self._op(self._d[right], sm)):
						sm = self._op(self._d[right], sm)
						right -= 1
				return right + 1 - self._size
			sm = self._op(self._d[right], sm)
		return 0

	def _update(self, k: int) -> None:
		self._d[k] = self._op(self._d[2 * k], self._d[2 * k + 1])

	def _all_apply(self, k: int, f: typing.Any) -> None:
		self._d[k] = self._mapping(f, self._d[k])
		if k < self._size:
			self._lz[k] = self._composition(f, self._lz[k])

	def _push(self, k: int) -> None:
		self._all_apply(2 * k, self._lz[k])
		self._all_apply(2 * k + 1, self._lz[k])
		self._lz[k] = self._id

	def _ceil_pow2(self, n: int) -> int:
		x = 0
		while 1 << x < n:
			x += 1
		return x
(N, Q) = map(int, input().split())
mod = 998244353
A = [pow(10, N - 1 - i, mod) * (1 << 32 | 1) for i in range(N)]
mask = (1 << 32) - 1

def op(x, y):
	(x1, x2) = (x >> 32, x & mask)
	(y1, y2) = (y >> 32, y & mask)
	(z1, z2) = ((x1 + y1) % mod, (x2 + y2) % mod)
	return z1 << 32 | z2
e = 0

def mapping(f, x):
	if f == id_:
		return x
	(x1, x2) = (x >> 32, x & mask)
	(z1, z2) = (f * x2 % mod, x2)
	return z1 << 32 | z2

def composition(f, g):
	if f == id_:
		(f, g) = (g, f)
	return f
id_ = -1
seg = LazySegTree(op, e, mapping, composition, id_, A)
for i in range(Q):
	(l, r, d) = map(int, input().split())
	seg.apply(l - 1, r, d)
	print(seg.all_prod() >> 32)


import sys
sys.setrecursionlimit(10 ** 7)

def MI():
	return map(int, sys.stdin.readline().rstrip().split())
(N, Q) = MI()
mod = 998244353
power = [1]
for i in range(N):
	power.append(power[-1] * 10 % mod)
t = pow(9, mod - 2, mod)

class LazySegTree:

	def __init__(self, N, X_func, A_func, operate, X_unit, A_unit):
		self.N = N
		self.X_func = X_func
		self.A_func = A_func
		self.operate = operate
		self.X_unit = X_unit
		self.A_unit = A_unit
		self.X = [self.X_unit] * (2 * self.N)
		self.A = [self.A_unit] * (2 * self.N)
		self.size = [0] * (2 * self.N)

	def build(self, init_value):
		for i in range(self.N):
			self.X[self.N + i] = init_value[i]
			self.size[self.N + i] = 1
		for i in range(self.N - 1, 0, -1):
			self.X[i] = self.X_func(self.X[i << 1], self.X[i << 1 | 1])
			self.size[i] = self.size[i << 1] + self.size[i << 1 | 1]

	def update(self, i, x):
		i += self.N
		self.X[i] = x
		i >>= 1
		while i:
			self.X[i] = self.X_func(self.X[i << 1], self.X[i << 1 | 1])
			i >>= 1

	def eval_at(self, i):
		return self.operate(self.X[i], self.A[i], self.size[i])

	def eval_above(self, i):
		i >>= 1
		while i:
			self.X[i] = self.X_func(self.eval_at(i << 1), self.eval_at(i << 1 | 1))
			i >>= 1

	def propagate_at(self, i):
		self.X[i] = self.operate(self.X[i], self.A[i], self.size[i])
		self.A[i << 1] = self.A_func(self.A[i << 1], self.A[i])
		self.A[i << 1 | 1] = self.A_func(self.A[i << 1 | 1], self.A[i])
		self.A[i] = self.A_unit

	def propagate_above(self, i):
		H = i.bit_length()
		for h in range(H, 0, -1):
			self.propagate_at(i >> h)

	def fold(self, L, R):
		L += self.N
		R += self.N
		L0 = L // (L & -L)
		R0 = R // (R & -R) - 1
		self.propagate_above(L0)
		self.propagate_above(R0)
		vL = self.X_unit
		vR = self.X_unit
		while L < R:
			if L & 1:
				vL = self.X_func(vL, self.eval_at(L))
				L += 1
			if R & 1:
				R -= 1
				vR = self.X_func(self.eval_at(R), vR)
			L >>= 1
			R >>= 1
		return self.X_func(vL, vR)

	def operate_range(self, L, R, x):
		L += self.N
		R += self.N
		L0 = L // (L & -L)
		R0 = R // (R & -R) - 1
		self.propagate_above(L0)
		self.propagate_above(R0)
		while L < R:
			if L & 1:
				self.A[L] = self.A_func(self.A[L], x)
				L += 1
			if R & 1:
				R -= 1
				self.A[R] = self.A_func(self.A[R], x)
			L >>= 1
			R >>= 1
		self.eval_above(L0)
		self.eval_above(R0)

def X_func(x, y):
	(x1, x2) = (x >> 18, x & (1 << 18) - 1)
	(y1, y2) = (y >> 18, y & (1 << 18) - 1)
	return ((x1 * power[y2] + y1) % mod << 18) + x2 + y2

def A_func(a, b):
	if b == 0:
		return a
	return b

def operate(x, a, r):
	if a == 0:
		return x
	(x1, x2) = (x >> 18, x & (1 << 18) - 1)
	return (a * (power[x2] - 1) * t % mod << 18) + x2
LST = LazySegTree(N, X_func, A_func, operate, 0, 0)
LST.build([(1 << 18) + 1] * N)
for _ in range(Q):
	(l, r, d) = MI()
	LST.operate_range(l - 1, r, d)
	print(LST.fold(0, N) >> 18)


import sys

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

def read_int():
	return int(sys.stdin.readline().strip())

def read_ints():
	return map(int, sys.stdin.readline().strip().split())

def read_str_split():
	return list(sys.stdin.readline().strip())

def read_int_list():
	return list(map(int, sys.stdin.readline().strip().split()))

class lazy_segtree:

	def __init__(self, op, e, mapping, composition, id, v: list):
		self.op = op
		self.e = e
		self.mapping = mapping
		self.composition = composition
		self.id = id
		self._n = len(v)
		self.log = ceil_pow2(self._n)
		self.size = 1 << self.log
		self.lz = [self.id()] * self.size
		self.d = [self.e()] * (2 * self.size)
		for i in range(self._n):
			self.d[self.size + i] = v[i]
		for i in range(self.size - 1, 0, -1):
			self.__update(i)

	def set_(self, p: int, x: int):
		assert 0 <= p and p < self._n
		p += self.size
		for i in range(self.log, 0, -1):
			self.__push(p >> i)
		self.d[p] = x
		for i in range(1, self.log + 1):
			self.__update(p >> 1)

	def get(self, p: int):
		assert 0 <= p and p < self._n
		p += self.size
		for i in range(self.log, 0, -1):
			self.__push(p >> i)
		return self.d[p]

	def prod(self, l: int, r: int):
		assert 0 <= l and l <= r and (r <= self._n)
		if l == r:
			return self.e()
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.__push(l >> i)
			if r >> i << i != r:
				self.__push(r >> i)
		(sml, smr) = (self.e(), self.e())
		while l < r:
			if l & 1:
				sml = self.op(sml, self.d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.d[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def all_prod(self):
		return self.d[1]

	def apply_sub(self, p: int, f):
		assert 0 <= p and p < self._n
		p += self.size
		for i in range(self.log, 0, -1):
			self.__push(p >> i)
		self.d[p] = self.mapping(f, self.d[p])
		for i in range(1, self.log + 1):
			self.__update(p >> 1)

	def apply(self, l: int, r: int, f):
		assert 0 <= l and l <= r and (r <= self._n)
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.__push(l >> i)
			if r >> i << i != r:
				self.__push(r - 1 >> i)
		(l2, r2) = (l, r)
		while l < r:
			if l & 1:
				self.__all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.__all_apply(r, f)
			l >>= 1
			r >>= 1
		(l, r) = (l2, r2)
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.__update(l >> i)
			if r >> i << i != r:
				self.__update(r >> i)

	def max_right(self, l: int, g):
		assert 0 <= l and l <= self._n
		if l == self._n:
			return self._n
		l += self.size
		for i in range(self.log, 0, -1):
			self.__push(l >> i)
		sm = self.e()
		while True:
			while l % 2 == 0:
				l >>= 1
			if not g(self.op(sm, self.d[l])):
				while l < self.size:
					self.__push(l)
					l = 2 * l
					if g(self.op(sm, self.d[l])):
						sm = self.op(sm, self.d[l])
						l += 1
				return l - self.size
			sm = self.op(sm, self.d[l])
			l += 1
			if l & -l == l:
				break
		return self._n

	def min_left(self, r: int, g):
		assert 0 <= r and r <= self._n
		if r == 0:
			return 0
		r += self.size
		for i in range(self.log, 0, -1):
			self.__push(r >> i)
		sm = self.e()
		while True:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(self.op(self.d[r], sm)):
				while r < self.size:
					self.__push(r)
					r = 2 * r + 1
					if g(self.op(self.d[r], sm)):
						sm = self.op(self.d[r], sm)
						r -= 1
				return r + 1 - self.size
			sm = self.op(self.d[r], sm)
			if r & -r == r:
				break
		return 0

	def __update(self, k: int):
		self.d[k] = self.op(self.d[k * 2], self.d[k * 2 + 1])

	def __all_apply(self, k: int, f):
		self.d[k] = self.mapping(f, self.d[k])
		if k < self.size:
			self.lz[k] = self.composition(f, self.lz[k])

	def __push(self, k: int):
		self.__all_apply(2 * k, self.lz[k])
		self.__all_apply(2 * k + 1, self.lz[k])
		self.lz[k] = self.id()

def ceil_pow2(n: int) -> int:
	x = 0
	while 1 << x < n:
		x += 1
	return x

class S:

	def __init__(self, a: int, sz: int, rp: int):
		self.a = a
		self.sz = sz
		self.rp = rp
p = 998244353

def op(l, r):
	(l1, l2) = (l >> 32, l & (1 << 32) - 1)
	(r1, r2) = (r >> 32, r & (1 << 32) - 1)
	return ((l1 + r1) % p << 32) + (l2 + r2) % p

def e():
	return 0

def mapping(l, r):
	(l1, l2) = (l >> 32, l & (1 << 32) - 1)
	(r1, r2) = (r >> 32, r & (1 << 32) - 1)
	if l1 == 0:
		return r
	return (r2 * l1 % p << 32) + r2

def composition(l, r):
	(l1, l2) = (l >> 32, l & (1 << 32) - 1)
	(r1, r2) = (r >> 32, r & (1 << 32) - 1)
	if l1 == 0:
		return r
	return l

def id():
	return 0

def Main():
	(n, q) = read_ints()
	a = [(pow(10, n - i - 1, p) << 32) + pow(10, n - i - 1, p) for i in range(n)]
	seg = lazy_segtree(op, e, mapping, composition, id, a)
	for i in range(q):
		(l, r, d) = read_ints()
		seg.apply(~-l, r, (d << 32) + i)
		print(seg.all_prod() >> 32)
Main()


class lazySegTree:

	def __init__(s, op, e, mapping, composition, id, v):
		if type(v) is int:
			v = [e()] * v
		s._n = len(v)
		s.log = s.ceil_pow2(s._n)
		s.size = 1 << s.log
		s.d = [e()] * (2 * s.size)
		s.lz = [id()] * s.size
		s.e = e
		s.op = op
		s.mapping = mapping
		s.composition = composition
		s.id = id
		for i in range(s._n):
			s.d[s.size + i] = v[i]
		for i in range(s.size - 1, 0, -1):
			s.update(i)

	def set(s, p, x):
		p += s.size
		for i in range(s.log, 0, -1):
			s.push(p >> i)
		s.d[p] = x
		for i in range(1, s.log + 1):
			s.update(p >> i)

	def get(s, p):
		p += s.size
		for i in range(s.log, 0, -1):
			s.push(p >> i)
		return s.d[p]

	def prod(s, l, r):
		if l == r:
			return s.e()
		l += s.size
		r += s.size
		for i in range(s.log, 0, -1):
			if l >> i << i != l:
				s.push(l >> i)
			if r >> i << i != r:
				s.push(r >> i)
		(sml, smr) = (s.e(), s.e())
		while l < r:
			if l & 1:
				sml = s.op(sml, s.d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = s.op(s.d[r], smr)
			l >>= 1
			r >>= 1
		return s.op(sml, smr)

	def all_prod(s):
		return s.d[1]

	def apply(s, p, f):
		p += s.size
		for i in range(s.log, 0, -1):
			s.push(p >> i)
		s.d[p] = s.mapping(f, s.d[p])
		for i in range(1, s.log + 1):
			s.update(p >> i)

	def apply(s, l, r, f):
		if l == r:
			return
		l += s.size
		r += s.size
		for i in range(s.log, 0, -1):
			if l >> i << i != l:
				s.push(l >> i)
			if r >> i << i != r:
				s.push(r - 1 >> i)
		(l2, r2) = (l, r)
		while l < r:
			if l & 1:
				sml = s.all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				smr = s.all_apply(r, f)
			l >>= 1
			r >>= 1
		(l, r) = (l2, r2)
		for i in range(1, s.log + 1):
			if l >> i << i != l:
				s.update(l >> i)
			if r >> i << i != r:
				s.update(r - 1 >> i)

	def max_right(s, l, g):
		if l == s._n:
			return s._n
		l += s.size
		for i in range(s.log, 0, -1):
			s.push(l >> i)
		sm = s.e()
		while True:
			while l % 2 == 0:
				l >>= 1
			if not g(s.op(sm, s.d[l])):
				while l < s.size:
					s.push(l)
					l = 2 * l
					if g(s.op(sm, s.d[l])):
						sm = s.op(sm, s.d[l])
						l += 1
				return l - s.size
			sm = s.op(sm, s.d[l])
			l += 1
			if l & -l == l:
				break
		return s._n

	def min_left(s, r, g):
		if r == 0:
			return 0
		r += s.size
		for i in range(s.log, 0, -1):
			s.push(r - 1 >> i)
		sm = s.e()
		while True:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(s.op(s.d[r], sm)):
				while r < s.size:
					s.push(r)
					r = 2 * r + 1
					if g(s.op(s.d[r], sm)):
						sm = s.op(s.d[r], sm)
						r -= 1
				return r + 1 - s.size
			sm = s.op(s.d[r], sm)
			if r & -r == r:
				break
		return 0

	def update(s, k):
		s.d[k] = s.op(s.d[2 * k], s.d[2 * k + 1])

	def all_apply(s, k, f):
		s.d[k] = s.mapping(f, s.d[k])
		if k < s.size:
			s.lz[k] = s.composition(f, s.lz[k])

	def push(s, k):
		s.all_apply(2 * k, s.lz[k])
		s.all_apply(2 * k + 1, s.lz[k])
		s.lz[k] = s.id()

	def ceil_pow2(s, n):
		x = 0
		while 1 << x < n:
			x += 1
		return x

def e():
	return 0

def op(a, b):
	(a0, a1) = (a >> 18, a & (1 << 18) - 1)
	(b0, b1) = (b >> 18, b & (1 << 18) - 1)
	return ((a0 * pow(10, b1, MOD) + b0) % MOD << 18) + a1 + b1

def mapping(f, a):
	if f == 0:
		return a
	(a0, a1) = (a >> 18, a & (1 << 18) - 1)
	return (D[f][a1] << 18) + a1

def composition(f, g):
	if f == 0:
		return g
	return f

def id():
	return 0
(N, Q) = list(map(int, input().split()))
LRD = [list(map(int, input().split())) for _ in range(Q)]
MOD = 998244353
D = [[0]]
for i in range(1, 10):
	D.append([0])
	for j in range(N):
		D[i].append((D[i][-1] * 10 + i) % MOD)
a = [(1 << 18) + 1 for _ in range(N)]
seg = lazySegTree(op, e, mapping, composition, id, a)
for (l, r, d) in LRD:
	seg.apply(l - 1, r, d)
	ans = seg.all_prod()
	print(ans >> 18)


INF = 10 ** 18

class LazySegTree:

	def __init__(self, n, op, e, mapping, composition, id):
		self.n = n
		self.op = op
		self.e = e
		self.mapping = mapping
		self.composition = composition
		self.id = id
		self.log = (n - 1).bit_length()
		self.size = 1 << self.log
		self.data = [e] * (2 * self.size)
		self.lazy = [id] * self.size

	def update(self, k):
		self.data[k] = self.op(self.data[2 * k], self.data[2 * k + 1])

	def all_apply(self, k, f):
		self.data[k] = self.mapping(f, self.data[k])
		if k < self.size:
			self.lazy[k] = self.composition(f, self.lazy[k])

	def push(self, k):
		self.all_apply(2 * k, self.lazy[k])
		self.all_apply(2 * k + 1, self.lazy[k])
		self.lazy[k] = self.id

	def build(self, lis):
		for (i, l) in enumerate(lis, self.size):
			self.data[i] = l
		for i in range(self.size - 1, 0, -1):
			self.update(i)

	def set(self, p, x):
		p += self.size
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		self.data[p] = x
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def get(self, p):
		p += self.size
		for i in range(1, self.log + 1):
			self.push(p >> i)
		return self.data[p]

	def prod(self, l, r):
		if l == r:
			return self.e
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r >> i)
		sml = smr = self.e
		while l < r:
			if l & 1:
				sml = self.op(sml, self.data[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.data[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def all_prod(self):
		return self.data[1]

	def apply(self, p, f):
		p += self.size
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		self.data[p] = self.mapping(f, self.data[p])
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def range_apply(self, l, r, f):
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r - 1 >> i)
		l2 = l
		r2 = r
		while l2 < r2:
			if l2 & 1:
				self.all_apply(l2, f)
				l2 += 1
			if r2 & 1:
				r2 -= 1
				self.all_apply(r2, f)
			l2 >>= 1
			r2 >>= 1
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.update(l >> i)
			if r >> i << i != r:
				self.update(r - 1 >> i)

	def max_right(self, l, g):
		if l == self.n:
			return self.n
		l += self.size
		for i in range(self.log, 0, -1):
			self.push(l >> i)
		sm = self.e
		while True:
			while l % 2 == 0:
				l >>= 1
			if not g(self.op(sm, self.data[l])):
				while l < self.size:
					self.push(l)
					l <<= 1
					if g(self.op(sm, self.data[l])):
						sm = self.op(sm, self.data[l])
						l += 1
				return l - self.size
			sm = self.op(sm, self.data[l])
			l += 1
			if l & -l == l:
				return self.n

	def min_left(self, r, g):
		if r == 0:
			return 0
		r += self.size
		for i in range(self.log, 0, -1):
			self.push(r - 1 >> i)
		sm = self.e
		while True:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(self.op(self.data[r], sm)):
				while r < self.size:
					self.push(r)
					r = 2 * r + 1
					if g(self.op(self.data[r], sm)):
						sm = self.op(self.data[r], sm)
						r -= 1
				return r + 1 - self.size
			sm = self.op(self.data[r], sm)
			if r & -r == r:
				return 0
mod = 998244353
po32 = pow(2, 32)
(n, q) = map(int, input().split())

def op(x, y):
	(xv, xr) = divmod(x, po32)
	(yv, yr) = divmod(y, po32)
	return (xv + yv) % mod * po32 + (xr + yr) % mod

def mapping(p, x):
	(xv, xr) = divmod(x, po32)
	if p == INF:
		return x
	return p * xr % mod * po32 + xr

def composition(p, q):
	if p == INF:
		return q
	return p
lis = [0] * n
ten = 1
for i in range(n - 1, -1, -1):
	lis[i] = ten % mod
	ten = ten * 10 % mod
l = [i * po32 + i for i in lis]
e = 0
id = INF
lazyseg = LazySegTree(n, op, e, mapping, composition, id)
lazyseg.build(l)
for i in range(q):
	(l, r, d) = map(int, input().split())
	lazyseg.range_apply(l - 1, r, d)
	print(lazyseg.all_prod() // po32)


mod = 998244353
eps = 10 ** (-9)

def main():
	import sys
	input = sys.stdin.buffer.readline
	beki10 = [0] * ((1 << 19) + 1)
	beki10[0] = 1
	for i in range(20):
		beki10[1 << i] = pow(10, 1 << i, mod)

	def op(a, b, seg_len):
		return (a * beki10[seg_len] + b) % mod
	e = 0
	inv9 = pow(9, mod - 2, mod)

	def mapping(a, x, seg_len):
		return x * inv9 % mod * (beki10[seg_len] - 1) % mod

	def composition(x, y):
		return y
	id = -1

	class LazySegTree:

		def __init__(self, A, op=op, e=e, mapping=mapping, composition=composition, id=id, initialize=True):
			self.N = len(A)
			self.LV = (self.N - 1).bit_length()
			self.N0 = 1 << self.LV
			self.op = op
			self.e = e
			self.mapping = mapping
			self.composition = composition
			self.id = id
			if initialize:
				self.data = [self.e] * self.N0 + A + [self.e] * (self.N0 - self.N)
				seg_len = 1
				beki = self.N0 // 2
				for i in range(self.N0 - 1, 0, -1):
					self.data[i] = op(self.data[i * 2], self.data[i * 2 + 1], seg_len)
					if i == beki:
						seg_len <<= 1
						beki >>= 1
			else:
				self.data = [self.e] * (self.N0 * 2)
			self.lazy = [id] * (self.N0 * 2)

		def _ascend(self, i, seg_len):
			for _ in range(i.bit_length() - 1):
				i >>= 1
				self.data[i] = self.op(self.data[i * 2], self.data[i * 2 + 1], seg_len)
				seg_len <<= 1

		def _descend(self, idx):
			lv = idx.bit_length()
			seg_len = 1 << self.LV
			for j in range(lv - 1, 0, -1):
				seg_len >>= 1
				i = idx >> j
				x = self.lazy[i]
				if x == self.id:
					continue
				self.lazy[i * 2] = self.composition(self.lazy[i * 2], x)
				self.lazy[i * 2 + 1] = self.composition(self.lazy[i * 2 + 1], x)
				self.lazy[i] = self.id
				self.data[i * 2] = self.mapping(self.data[i * 2], x, seg_len)
				self.data[i * 2 + 1] = self.mapping(self.data[i * 2 + 1], x, seg_len)

		def apply(self, l, r, x):
			l += self.N0 - 1
			r += self.N0 - 1
			self._descend(l // (l & -l))
			self._descend(r // (r & -r) - 1)
			l_ori = l
			r_ori = r
			seg_len = 1
			while l < r:
				if l & 1:
					self.data[l] = self.mapping(self.data[l], x, seg_len)
					self.lazy[l] = self.composition(self.lazy[l], x)
					l += 1
				if r & 1:
					r -= 1
					self.data[r] = self.mapping(self.data[r], x, seg_len)
					self.lazy[r] = self.composition(self.lazy[r], x)
				l >>= 1
				r >>= 1
				seg_len <<= 1
			self._ascend(l_ori // (l_ori & -l_ori), l_ori & -l_ori)
			self._ascend(r_ori // (r_ori & -r_ori) - 1, r_ori & -r_ori)

		def query(self, l, r):
			l += self.N0 - 1
			r += self.N0 - 1
			self._descend(l // (l & -l))
			self._descend(r // (r & -r) - 1)
			ret_l = self.e
			ret_r = self.e
			seg_len = 1
			while l < r:
				if l & 1:
					ret_l = self.op(ret_l, self.data[l], seg_len)
					l += 1
				if r & 1:
					ret_r = self.op(self.data[r - 1], ret_r, seg_len)
					r -= 1
				l >>= 1
				r >>= 1
				seg_len <<= 1
			return self.op(ret_l, ret_r, 1)
	(N, Q) = map(int, input().split())
	N0 = 1 << (N - 1).bit_length()
	ST = LazySegTree([0] * (N0 - N) + [1] * N)
	inv10 = pow(10, mod - 2, mod)
	ans = [0] * Q
	for q in range(Q):
		(l, r, d) = map(int, input().split())
		ST.apply(N0 - N + l, N0 - N + r + 1, d)
		ans[q] = ST.query(N0 - N + 1, N0 + 1) * inv10 % mod
	print(*ans, sep='\n')
main()


(N, Q, *LRD) = [int(_) for _ in open(0).read().split()]
(L, R, D) = (LRD[::3], LRD[1::3], LRD[2::3])
mod = 998244353

class LazySegmentTree:

	def __init__(self, array, f, g, h, ti, ei):
		self.f = f
		self.g = g
		self.h = h
		self.ti = ti
		self.ei = ei
		self.height = height = len(array).bit_length()
		self.n = n = 2 ** height
		self.dat = dat = [ti] * n + array + [ti] * (n - len(array))
		self.laz = [ei] * (2 * n)
		for i in range(n - 1, 0, -1):
			dat[i] = f(dat[i << 1], dat[i << 1 | 1])

	def reflect(self, k):
		dat = self.dat
		ei = self.ei
		laz = self.laz
		g = self.g
		return self.dat[k] if laz[k] is ei else g(dat[k], laz[k])

	def evaluate(self, k):
		laz = self.laz
		ei = self.ei
		reflect = self.reflect
		dat = self.dat
		h = self.h
		if laz[k] is ei:
			return
		laz[k << 1 | 0] = h(laz[k << 1 | 0], laz[k])
		laz[k << 1 | 1] = h(laz[k << 1 | 1], laz[k])
		dat[k] = reflect(k)
		laz[k] = ei

	def thrust(self, k):
		height = self.height
		evaluate = self.evaluate
		for i in range(height, 0, -1):
			evaluate(k >> i)

	def recalc(self, k):
		dat = self.dat
		reflect = self.reflect
		f = self.f
		while k:
			k >>= 1
			dat[k] = f(reflect(k << 1 | 0), reflect(k << 1 | 1))

	def update(self, a, b, x):
		thrust = self.thrust
		n = self.n
		h = self.h
		laz = self.laz
		recalc = self.recalc
		a += n
		b += n - 1
		l = a
		r = b + 1
		thrust(a)
		thrust(b)
		while l < r:
			if l & 1:
				laz[l] = h(laz[l], x)
				l += 1
			if r & 1:
				r -= 1
				laz[r] = h(laz[r], x)
			l >>= 1
			r >>= 1
		recalc(a)
		recalc(b)

	def set_val(self, a, x):
		n = self.n
		thrust = self.thrust
		dat = self.dat
		laz = self.laz
		recalc = self.recalc
		ei = self.ei
		a += n
		thrust(a)
		dat[a] = x
		laz[a] = ei
		recalc(a)

	def query(self, a, b):
		f = self.f
		ti = self.ti
		n = self.n
		thrust = self.thrust
		reflect = self.reflect
		a += n
		b += n - 1
		thrust(a)
		thrust(b)
		l = a
		r = b + 1
		vl = vr = ti
		while l < r:
			if l & 1:
				vl = f(vl, reflect(l))
				l += 1
			if r & 1:
				r -= 1
				vr = f(reflect(r), vr)
			l >>= 1
			r >>= 1
		return f(vl, vr)
array = [pow(10, i, mod) * (2 ** 30 + 1) for i in range(N)][::-1]

def f(a, b):
	(qa, ra) = divmod(a, 2 ** 30)
	(qb, rb) = divmod(b, 2 ** 30)
	return (qa + qb) % mod * 2 ** 30 + (ra + rb) % mod

def g(a, b):
	(qa, ra) = divmod(a, 2 ** 30)
	return ra * b % mod * 2 ** 30 + ra
h = lambda a, b: b
ti = 0
ei = 0
lst = LazySegmentTree(array=array, ti=ti, ei=ei, f=f, g=g, h=h)
ans = []
for (l, r, d) in zip(L, R, D):
	lst.update(l - 1, r, d)
	ans += [lst.query(0, N) // 2 ** 30]
print('\n'.join(map(str, ans)))


class LazySegmentTree:
	__slots__ = ['n', 'data', 'lazy', 'me', 'oe', 'fmm', 'fmo', 'foo']

	def __init__(self, monoid_data, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator, func_operator_operator):
		self.me = monoid_identity
		self.oe = operator_identity
		self.fmm = func_monoid_monoid
		self.fmo = func_monoid_operator
		self.foo = func_operator_operator
		self.n = len(monoid_data)
		self.data = monoid_data * 2
		for i in range(self.n - 1, 0, -1):
			self.data[i] = self.fmm(self.data[2 * i], self.data[2 * i + 1])
		self.lazy = [self.oe] * (self.n * 2)

	def replace(self, index, value):
		index += self.n
		for shift in range(index.bit_length() - 1, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		self.data[index] = value
		self.lazy[index] = self.oe
		i = index
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def effect(self, l, r, operator):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 //= 2
		while l0 > r0:
			indices.append(l0)
			l0 //= 2
		while l0 and l0 != r0:
			indices.append(r0)
			r0 //= 2
			if l0 == r0:
				break
			indices.append(l0)
			l0 //= 2
		while r0:
			indices.append(r0)
			r0 //= 2
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		while l < r:
			if l % 2:
				self.lazy[l] = self.foo(self.lazy[l], operator)
				l += 1
			if r % 2:
				r -= 1
				self.lazy[r] = self.foo(self.lazy[r], operator)
			l //= 2
			r //= 2
		for i in indices:
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def folded(self, l, r):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 //= 2
		while l0 > r0:
			indices.append(l0)
			l0 //= 2
		while l0 and l0 != r0:
			indices.append(r0)
			r0 //= 2
			if l0 == r0:
				break
			indices.append(l0)
			l0 //= 2
		while r0:
			indices.append(r0)
			r0 //= 2
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		left_folded = self.me
		right_folded = self.me
		while l < r:
			if l % 2:
				left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
				l += 1
			if r % 2:
				r -= 1
				right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
			l //= 2
			r //= 2
		return self.fmm(left_folded, right_folded)
import sys
input = sys.stdin.readline
mod = 998244353
(n, q) = map(int, input().split())
one = [0] * (n + 1)
ten = [1] * (n + 1)
for i in range(n):
	one[i + 1] = (one[i] * 10 + 1) % mod
	ten[i + 1] = ten[i] * 10 % mod

def fmm(m1, m2):
	(l1, d1) = m1
	(l2, d2) = m2
	d = d1 * ten[l2] + d2
	d %= mod
	l = l1 + l2
	return (l, d)

def fmo(m1, o1):
	if o1 == -1:
		return m1
	(l1, d1) = m1
	d = one[l1] * o1
	d %= mod
	return (l1, d)

def foo(o1, o2):
	if o2 == -1:
		return o1
	return o2
seg = LazySegmentTree([(1, 1)] * n, (0, 0), -1, fmm, fmo, foo)
for _ in range(q):
	(l, r, d) = map(int, input().split())
	l -= 1
	seg.effect(l, r, d)
	print(seg.folded(0, n)[1])


class LazySegmentTree:
	__slots__ = ['n', 'original_size', 'log', 'data', 'lazy', 'me', 'oe', 'fmm', 'fmo', 'foo']

	def __init__(self, length_or_list, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator, func_operator_operator):
		self.me = monoid_identity
		self.oe = operator_identity
		self.fmm = func_monoid_monoid
		self.fmo = func_monoid_operator
		self.foo = func_operator_operator
		if isinstance(length_or_list, int):
			self.original_size = length_or_list
			self.log = (self.original_size - 1).bit_length()
			self.n = 1 << self.log
			self.data = [self.me] * (self.n * 2)
			self.lazy = [self.oe] * (self.n * 2)
		elif isinstance(length_or_list, list):
			self.original_size = len(length_or_list)
			self.log = (self.original_size - 1).bit_length()
			self.n = 1 << self.log
			self.data = [self.me] * self.n + length_or_list + [self.me] * (self.n - self.original_size)
			for i in range(self.n - 1, 0, -1):
				self.data[i] = self.fmm(self.data[2 * i], self.data[2 * i + 1])
			self.lazy = [self.oe] * (self.n * 2)
		else:
			raise TypeError(f"The argument 'length_or_list' must be an integer or a list, not {type(length_or_list).__name__}")

	def replace(self, index, value):
		if index < 0:
			index += self.original_size
		if not 0 <= index < self.original_size:
			raise IndexError('LazySegmentTree index out of range')
		index += self.n
		for shift in range(self.log, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		self.data[index] = value
		self.lazy[index] = self.oe
		i = index
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def __getitem__(self, index):
		if index < 0:
			index += self.original_size
		if not 0 <= index < self.original_size:
			raise IndexError('LazySegmentTree index out of range')
		index += self.n
		for shift in range(self.log, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		return self.data[index]

	def effect_single(self, index, operator):
		if index < 0:
			index += self.original_size
		if not 0 <= index < self.original_size:
			raise IndexError('LazySegmentTree index out of range')
		index += self.n
		for shift in range(self.log, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		self.data[index] = self.fmo(self.data[index], operator)
		i = index
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def effect(self, l, r, operator):
		if l < 0:
			l += self.original_size
		if r < 0:
			r += self.original_size
		if not 0 <= l <= r <= self.original_size:
			raise IndexError('LazySegmentTree index out of range')
		if l == r:
			return
		l += self.n
		r += self.n
		l0 = l
		r0 = r - 1
		while l0 % 2 == 0:
			l0 //= 2
		while r0 % 2 == 1:
			r0 //= 2
		for shift in range(self.log, 0, -1):
			i = l >> shift
			if i << shift != l:
				self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
				self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
				self.data[i] = self.fmo(self.data[i], self.lazy[i])
				self.lazy[i] = self.oe
			i = r >> shift
			if i << shift != r:
				self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
				self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
				self.data[i] = self.fmo(self.data[i], self.lazy[i])
				self.lazy[i] = self.oe
		while l < r:
			if l % 2:
				self.lazy[l] = self.foo(self.lazy[l], operator)
				l += 1
			if r % 2:
				r -= 1
				self.lazy[r] = self.foo(self.lazy[r], operator)
			l //= 2
			r //= 2
		i = l0
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe
		i = r0
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def folded(self, l, r):
		if l < 0:
			l += self.original_size
		if r < 0:
			r += self.original_size
		if not 0 <= l <= r <= self.original_size:
			raise IndexError('LazySegmentTree index out of range')
		if l == r:
			return self.me
		l += self.n
		r += self.n
		for shift in range(self.log, 0, -1):
			i = l >> shift
			if i << shift != l:
				self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
				self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
				self.data[i] = self.fmo(self.data[i], self.lazy[i])
				self.lazy[i] = self.oe
			i = r >> shift
			if i << shift != r:
				self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
				self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
				self.data[i] = self.fmo(self.data[i], self.lazy[i])
				self.lazy[i] = self.oe
		left_folded = self.me
		right_folded = self.me
		while l < r:
			if l % 2:
				left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
				l += 1
			if r % 2:
				r -= 1
				right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
			l //= 2
			r //= 2
		return self.fmm(left_folded, right_folded)

	def all_folded(self):
		return self.data[1]

	def max_right(self, l, f):
		if l < 0:
			l += self.original_size
		if not 0 <= l <= self.original_size:
			raise IndexError('LazySegmentTree index out of range')
		assert f(self.me)
		if l == self.original_size:
			return self.original_size
		l += self.n
		for shift in range(self.log, 0, -1):
			i = l >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		left_folded = self.me
		while True:
			while l % 2 == 0:
				l //= 2
			if not f(self.fmm(left_folded, self.data[l])):
				while l < self.n:
					i = l
					self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
					self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
					self.data[i] = self.fmo(self.data[i], self.lazy[i])
					self.lazy[i] = self.oe
					l *= 2
					if f(self.fmm(left_folded, self.data[l])):
						left_folded = self.fmm(left_folded, self.data[l])
						l += 1
				return l - self.n
			left_folded = self.fmm(left_folded, self.data[l])
			l += 1
			if l == l & -l:
				break
		return self.original_size

	def min_left(self, r, f):
		if r < 0:
			r += self.original_size
		if not 0 <= r <= self.original_size:
			raise IndexError('LazySegmentTree index out of range')
		assert f(self.me)
		if r == 0:
			return 0
		r += self.n
		for shift in range(self.log, 0, -1):
			i = r >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		right_folded = self.me
		while True:
			r -= 1
			while r > 1 and r % 2:
				r //= 2
			if not f(self.fmm(self.data[r], right_folded)):
				while r < self.n:
					i = r
					self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
					self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
					self.data[i] = self.fmo(self.data[i], self.lazy[i])
					self.lazy[i] = self.oe
					r = 2 * r + 1
					if f(self.fmm(self.data[r], right_folded)):
						right_folded = self.fmm(self.data[r], right_folded)
						r -= 1
				return r + 1 - self.n
			right_folded = self.fmm(self.data[r], right_folded)
			if r == r & -r:
				break
		return 0
MOD = 998244353
mask32 = (1 << 32) - 1
import sys
input = sys.stdin.buffer.readline
read = sys.stdin.buffer.read
(N, Q) = map(int, input().split())
pw = [1]
for _ in range(N + 2):
	pw.append(pw[-1] * 10 % MOD)

def fmm(m1, m2):
	v1 = m1 >> 32
	l1 = m1 & mask32
	v2 = m2 >> 32
	l2 = m2 & mask32
	v = (v1 * pw[l2] + v2) % MOD
	l = l1 + l2
	return (v << 32) + l
inv9 = pow(9, MOD - 2, MOD)

def fmo(m, o):
	if o == -1:
		return m
	else:
		l = m & mask32
		v = o * (pw[l] - 1) * inv9 % MOD
		return (v << 32) + l

def foo(o1, o2):
	if o2 == -1:
		return o1
	else:
		return o2
lst = LazySegmentTree([(1 << 32) + 1] * N, 0, -1, fmm, fmo, foo)
LRDs = map(int, read().split())
for (L, R, D) in zip(LRDs, LRDs, LRDs):
	lst.effect(L - 1, R, D)
	print(lst.all_folded() >> 32)


import typing
import sys
MOD = 998244353

def main(N, Q, LRD):
	inv9 = pow(9, MOD - 2, MOD)
	tree = LazySegTree(op=lambda x, y: ((x[0] * y[1] % MOD + y[0]) % MOD, x[1] * y[1] % MOD), e=(0, 1), mapping=lambda f, s: s if f == 0 else ((s[1] - 1) * inv9 * f % MOD, s[1]), composition=lambda f, g: g if f == 0 else f, id_=0, v=[(1, 10)] * N)
	for (l, r, d) in LRD:
		l -= 1
		tree.apply(l, r, d)
		print(tree.all_prod()[0])

def _ceil_pow2(n: int) -> int:
	x = 0
	while 1 << x < n:
		x += 1
	return x

def _bsf(n: int) -> int:
	x = 0
	while n % 2 == 0:
		x += 1
		n //= 2
	return x

class LazySegTree:

	def __init__(self, op: typing.Callable[[typing.Any, typing.Any], typing.Any], e: typing.Any, mapping: typing.Callable[[typing.Any, typing.Any], typing.Any], composition: typing.Callable[[typing.Any, typing.Any], typing.Any], id_: typing.Any, v: typing.Union[int, typing.List[typing.Any]]) -> None:
		self._op = op
		self._e = e
		self._mapping = mapping
		self._composition = composition
		self._id = id_
		if isinstance(v, int):
			v = [e] * v
		self._n = len(v)
		self._log = _ceil_pow2(self._n)
		self._size = 1 << self._log
		self._d = [e] * (2 * self._size)
		self._lz = [self._id] * self._size
		for i in range(self._n):
			self._d[self._size + i] = v[i]
		for i in range(self._size - 1, 0, -1):
			self._update(i)

	def set(self, p: int, x: typing.Any) -> None:
		assert 0 <= p < self._n
		p += self._size
		for i in range(self._log, 0, -1):
			self._push(p >> i)
		self._d[p] = x
		for i in range(1, self._log + 1):
			self._update(p >> i)

	def get(self, p: int) -> typing.Any:
		assert 0 <= p < self._n
		p += self._size
		for i in range(self._log, 0, -1):
			self._push(p >> i)
		return self._d[p]

	def prod(self, left: int, right: int) -> typing.Any:
		assert 0 <= left <= right <= self._n
		if left == right:
			return self._e
		left += self._size
		right += self._size
		for i in range(self._log, 0, -1):
			if left >> i << i != left:
				self._push(left >> i)
			if right >> i << i != right:
				self._push(right >> i)
		sml = self._e
		smr = self._e
		while left < right:
			if left & 1:
				sml = self._op(sml, self._d[left])
				left += 1
			if right & 1:
				right -= 1
				smr = self._op(self._d[right], smr)
			left >>= 1
			right >>= 1
		return self._op(sml, smr)

	def all_prod(self) -> typing.Any:
		return self._d[1]

	def apply(self, left: int, right: typing.Optional[int]=None, f: typing.Optional[typing.Any]=None):
		assert f is not None
		if right is None:
			p = left
			assert 0 <= left < self._n
			p += self._size
			for i in range(self._log, 0, -1):
				self._push(p >> i)
			self._d[p] = self._mapping(f, self._d[p])
			for i in range(1, self._log + 1):
				self._update(p >> i)
		else:
			assert 0 <= left <= right <= self._n
			if left == right:
				return
			left += self._size
			right += self._size
			for i in range(self._log, 0, -1):
				if left >> i << i != left:
					self._push(left >> i)
				if right >> i << i != right:
					self._push(right - 1 >> i)
			l2 = left
			r2 = right
			while left < right:
				if left & 1:
					self._all_apply(left, f)
					left += 1
				if right & 1:
					right -= 1
					self._all_apply(right, f)
				left >>= 1
				right >>= 1
			left = l2
			right = r2
			for i in range(1, self._log + 1):
				if left >> i << i != left:
					self._update(left >> i)
				if right >> i << i != right:
					self._update(right - 1 >> i)

	def max_right(self, left: int, g: typing.Callable[[typing.Any], bool]) -> int:
		assert 0 <= left <= self._n
		assert g(self._e)
		if left == self._n:
			return self._n
		left += self._size
		for i in range(self._log, 0, -1):
			self._push(left >> i)
		sm = self._e
		first = True
		while first or left & -left != left:
			first = False
			while left % 2 == 0:
				left >>= 1
			if not g(self._op(sm, self._d[left])):
				while left < self._size:
					self._push(left)
					left *= 2
					if g(self._op(sm, self._d[left])):
						sm = self._op(sm, self._d[left])
						left += 1
				return left - self._size
			sm = self._op(sm, self._d[left])
			left += 1
		return self._n

	def min_left(self, right: int, g: typing.Any) -> int:
		assert 0 <= right <= self._n
		assert g(self._e)
		if right == 0:
			return 0
		right += self._size
		for i in range(self._log, 0, -1):
			self._push(right - 1 >> i)
		sm = self._e
		first = True
		while first or right & -right != right:
			first = False
			right -= 1
			while right > 1 and right % 2:
				right >>= 1
			if not g(self._op(self._d[right], sm)):
				while right < self._size:
					self._push(right)
					right = 2 * right + 1
					if g(self._op(self._d[right], sm)):
						sm = self._op(self._d[right], sm)
						right -= 1
				return right + 1 - self._size
			sm = self._op(self._d[right], sm)
		return 0

	def _update(self, k: int) -> None:
		self._d[k] = self._op(self._d[2 * k], self._d[2 * k + 1])

	def _all_apply(self, k: int, f: typing.Any) -> None:
		self._d[k] = self._mapping(f, self._d[k])
		if k < self._size:
			self._lz[k] = self._composition(f, self._lz[k])

	def _push(self, k: int) -> None:
		self._all_apply(2 * k, self._lz[k])
		self._all_apply(2 * k + 1, self._lz[k])
		self._lz[k] = self._id
input = sys.stdin.readline
(N, Q) = map(int, input().split())
LRD = [tuple(map(int, input().split())) for _ in range(Q)]
main(N, Q, LRD)


import sys
sys.setrecursionlimit(10 ** 7)
input = sys.stdin.buffer.readline
mod = 998244353
INF = float('inf')

class lazySegTree(object):

	def __init__(self, N):
		self.N = N
		self.LV = (N - 1).bit_length()
		self.N0 = 2 ** self.LV
		self.data = [0] * (2 * self.N0)
		self.lazy = [0] * (2 * self.N0)
		self.size = [1] * (2 * self.N0)
		for i in range(self.N):
			self.size[self.N0 - 1 + i] = pow(10, self.N - i - 1, mod)
		for i in range(self.N0 - 2, -1, -1):
			self.size[i] = (self.size[2 * i + 1] + self.size[2 * i + 2]) % mod

	def initialize(self):
		for i in range(self.N):
			self.data[self.N0 - 1 + i] = pow(10, self.N - i - 1, mod)
		for i in range(self.N0 - 2, -1, -1):
			self.data[i] = (self.data[2 * i + 1] + self.data[2 * i + 2]) % mod

	def gindex(self, l, r):
		L = l + self.N0
		L >>= 1
		R = r + self.N0
		R >>= 1
		if l & 1:
			lc = 0
		else:
			lc = (L & -L).bit_length()
		if r & 1:
			rc = 0
		else:
			rc = (R & -R).bit_length()
		for i in range(self.LV):
			if rc <= i:
				yield R
			if L < R and lc <= i:
				yield L
			L >>= 1
			R >>= 1

	def propagates(self, *ids):
		for i in reversed(ids):
			v = self.lazy[i - 1]
			if not v:
				continue
			self.lazy[2 * i - 1] = v
			self.lazy[2 * i] = v
			self.data[2 * i - 1] = v * self.size[2 * i - 1]
			self.data[2 * i] = v * self.size[2 * i]
			self.lazy[i - 1] = 0

	def update(self, l, r, x):
		(*ids,) = self.gindex(l, r + 1)
		self.propagates(*ids)
		L = self.N0 + l
		R = self.N0 + r + 1
		while L < R:
			if R & 1:
				R -= 1
				self.lazy[R - 1] = x
				self.data[R - 1] = x * self.size[R - 1]
			if L & 1:
				self.lazy[L - 1] = x
				self.data[L - 1] = x * self.size[L - 1]
				L += 1
			L >>= 1
			R >>= 1
		for i in ids:
			self.data[i - 1] = (self.data[2 * i - 1] + self.data[2 * i]) % mod

	def query(self, l, r):
		self.propagates(*self.gindex(l, r + 1))
		L = self.N0 + l
		R = self.N0 + r + 1
		s = 0
		while L < R:
			if R & 1:
				R -= 1
				s = (s + self.data[R - 1]) % mod
			if L & 1:
				s = (s + self.data[L - 1]) % mod
				L += 1
			L >>= 1
			R >>= 1
		return s
(N, Q) = map(int, input().split())
lSeg = lazySegTree(N)
lSeg.initialize()
for i in range(Q):
	(L, R, D) = map(int, input().split())
	L -= 1
	R -= 1
	lSeg.update(L, R, D)
	ans = lSeg.query(0, N - 1)
	ans %= mod
	print(ans)


import typing

def _ceil_pow2(n: int) -> int:
	x = 0
	while 1 << x < n:
		x += 1
	return x

class LazySegTree:

	def __init__(self, op: typing.Callable[[typing.Any, typing.Any], typing.Any], e: typing.Any, mapping: typing.Callable[[typing.Any, typing.Any], typing.Any], composition: typing.Callable[[typing.Any, typing.Any], typing.Any], id_: typing.Any, v: typing.Union[int, typing.List[typing.Any]]) -> None:
		self._op = op
		self._e = e
		self._mapping = mapping
		self._composition = composition
		self._id = id_
		if isinstance(v, int):
			v = [e] * v
		self._n = len(v)
		self._log = _ceil_pow2(self._n)
		self._size = 1 << self._log
		self._d = [e] * (2 * self._size)
		self._lz = [self._id] * self._size
		for i in range(self._n):
			self._d[self._size + i] = v[i]
		for i in range(self._size - 1, 0, -1):
			self._update(i)

	def set(self, p: int, x: typing.Any) -> None:
		assert 0 <= p < self._n
		p += self._size
		for i in range(self._log, 0, -1):
			self._push(p >> i)
		self._d[p] = x
		for i in range(1, self._log + 1):
			self._update(p >> i)

	def get(self, p: int) -> typing.Any:
		assert 0 <= p < self._n
		p += self._size
		for i in range(self._log, 0, -1):
			self._push(p >> i)
		return self._d[p]

	def prod(self, left: int, right: int) -> typing.Any:
		assert 0 <= left <= right <= self._n
		if left == right:
			return self._e
		left += self._size
		right += self._size
		for i in range(self._log, 0, -1):
			if left >> i << i != left:
				self._push(left >> i)
			if right >> i << i != right:
				self._push(right >> i)
		sml = self._e
		smr = self._e
		while left < right:
			if left & 1:
				sml = self._op(sml, self._d[left])
				left += 1
			if right & 1:
				right -= 1
				smr = self._op(self._d[right], smr)
			left >>= 1
			right >>= 1
		return self._op(sml, smr)

	def all_prod(self) -> typing.Any:
		return self._d[1]

	def apply(self, left: int, right: typing.Optional[int]=None, f: typing.Optional[typing.Any]=None):
		assert f is not None
		if right is None:
			p = left
			assert 0 <= left < self._n
			p += self._size
			for i in range(self._log, 0, -1):
				self._push(p >> i)
			self._d[p] = self._mapping(f, self._d[p])
			for i in range(1, self._log + 1):
				self._update(p >> i)
		else:
			assert 0 <= left <= right <= self._n
			if left == right:
				return
			left += self._size
			right += self._size
			for i in range(self._log, 0, -1):
				if left >> i << i != left:
					self._push(left >> i)
				if right >> i << i != right:
					self._push(right - 1 >> i)
			l2 = left
			r2 = right
			while left < right:
				if left & 1:
					self._all_apply(left, f)
					left += 1
				if right & 1:
					right -= 1
					self._all_apply(right, f)
				left >>= 1
				right >>= 1
			left = l2
			right = r2
			for i in range(1, self._log + 1):
				if left >> i << i != left:
					self._update(left >> i)
				if right >> i << i != right:
					self._update(right - 1 >> i)

	def max_right(self, left: int, g: typing.Callable[[typing.Any], bool]) -> int:
		assert 0 <= left <= self._n
		assert g(self._e)
		if left == self._n:
			return self._n
		left += self._size
		for i in range(self._log, 0, -1):
			self._push(left >> i)
		sm = self._e
		first = True
		while first or left & -left != left:
			first = False
			while left % 2 == 0:
				left >>= 1
			if not g(self._op(sm, self._d[left])):
				while left < self._size:
					self._push(left)
					left *= 2
					if g(self._op(sm, self._d[left])):
						sm = self._op(sm, self._d[left])
						left += 1
				return left - self._size
			sm = self._op(sm, self._d[left])
			left += 1
		return self._n

	def min_left(self, right: int, g: typing.Any) -> int:
		assert 0 <= right <= self._n
		assert g(self._e)
		if right == 0:
			return 0
		right += self._size
		for i in range(self._log, 0, -1):
			self._push(right - 1 >> i)
		sm = self._e
		first = True
		while first or right & -right != right:
			first = False
			right -= 1
			while right > 1 and right % 2:
				right >>= 1
			if not g(self._op(self._d[right], sm)):
				while right < self._size:
					self._push(right)
					right = 2 * right + 1
					if g(self._op(self._d[right], sm)):
						sm = self._op(self._d[right], sm)
						right -= 1
				return right + 1 - self._size
			sm = self._op(self._d[right], sm)
		return 0

	def _update(self, k: int) -> None:
		self._d[k] = self._op(self._d[2 * k], self._d[2 * k + 1])

	def _all_apply(self, k: int, f: typing.Any) -> None:
		self._d[k] = self._mapping(f, self._d[k])
		if k < self._size:
			self._lz[k] = self._composition(f, self._lz[k])

	def _push(self, k: int) -> None:
		self._all_apply(2 * k, self._lz[k])
		self._all_apply(2 * k + 1, self._lz[k])
		self._lz[k] = self._id
keta_to_mint10 = [0] * 300001
keta_to_mint = [0] * 300001
MOD = 998244353

def modinv(a, m):
	(b, u, v) = (m, 1, 0)
	while b:
		t = a // b
		a -= t * b
		(a, b) = (b, a)
		u -= t * v
		(u, v) = (v, u)
	u %= m
	return u

def main():

	def op(a, b):
		return ((a[0] * keta_to_mint10[b[1]] + b[0]) % MOD, a[1] + b[1])
	e = (0, 0)
	f_id = 0
	id_ = f_id

	def mapping(f, x):
		if f == f_id:
			return x
		else:
			return (keta_to_mint[x[1]] * f % MOD, x[1])

	def composition(f, g):
		if f == f_id:
			return g
		else:
			return f
	(n, q) = map(int, input().split())
	a = [(1, 1)] * n
	keta_to_mint10[0] = 1
	mod9 = modinv(9, MOD)
	for i in range(1, 200001):
		keta_to_mint10[i] = keta_to_mint10[i - 1] * 10 % MOD
		keta_to_mint[i] = (keta_to_mint10[i] - 1) * mod9 % MOD
	seg = LazySegTree(op, e, mapping, composition, id_, a)
	for _ in range(q):
		(l, r, d) = map(int, input().split())
		seg.apply(l - 1, r, d)
		ans = seg.all_prod()[0]
		print(ans)
main()


class LazySegmentTree:

	@classmethod
	def all_identity(cls, op, op_e, comp, comp_e, apply, size):
		size = 1 << (size - 1).bit_length()
		return cls(op, op_e, comp, comp_e, apply, [op_e] * (2 * size), [comp_e] * size)

	@classmethod
	def from_initial_data(cls, op, op_e, comp, comp_e, apply, data):
		size = 1 << (len(data) - 1).bit_length()
		temp = [op_e] * (2 * size)
		temp[size:size + len(data)] = data
		for i in reversed(range(size)):
			temp[i] = op(temp[2 * i], temp[2 * i + 1])
		return cls(op, op_e, comp, comp_e, apply, temp, [comp_e] * size)

	def __init__(self, op, op_e, comp, comp_e, apply, data, lazy):
		self.op = op
		self.op_e = op_e
		self.comp = comp
		self.comp_e = comp_e
		self.apply = apply
		self.data = data
		self.lazy = lazy
		self.size = len(self.data) // 2
		self.depth = self.size.bit_length() - 1
		self._l_indices = [0] * self.depth
		self._r_indices = [0] * self.depth

	def _update_indices(self, i, l):
		m = i // (i & -i)
		i >>= 1
		for k in range(self.depth):
			l[k] = i if i < m else 0
			i >>= 1

	def _propagate_top_down(self):
		data = self.data
		lazy = self.lazy
		apply = self.apply
		comp = self.comp
		comp_e = self.comp_e
		k = self.size >> 1
		for (i, j) in zip(reversed(self._l_indices), reversed(self._r_indices)):
			if i > 0:
				temp = lazy[i]
				if temp != comp_e:
					lazy[i] = comp_e
					a = i << 1
					b = a | 1
					data[a] = apply(data[a], temp, k)
					data[b] = apply(data[b], temp, k)
					if k > 1:
						lazy[a] = comp(lazy[a], temp)
						lazy[b] = comp(lazy[b], temp)
			if i < j:
				temp = lazy[j]
				if temp != comp_e:
					lazy[j] = comp_e
					a = j << 1
					b = a | 1
					data[a] = apply(data[a], temp, k)
					data[b] = apply(data[b], temp, k)
					if k > 1:
						lazy[a] = comp(lazy[a], temp)
						lazy[b] = comp(lazy[b], temp)
			k >>= 1

	def _propagate_bottom_up(self):
		data = self.data
		op = self.op
		for (i, j) in zip(self._l_indices, self._r_indices):
			if i < j:
				data[j] = op(data[j << 1], data[j << 1 | 1])
			if i > 0:
				data[i] = op(data[i << 1], data[i << 1 | 1])

	def update_interval(self, l, r, m):
		lazy = self.lazy
		data = self.data
		comp = self.comp
		apply = self.apply
		l += self.size
		r += self.size
		self._update_indices(l, self._l_indices)
		self._update_indices(r, self._r_indices)
		self._propagate_top_down()
		k = 1
		while l < r:
			if l & 1:
				data[l] = apply(data[l], m, k)
				if k > 1:
					lazy[l] = comp(lazy[l], m)
				l += 1
			if r & 1:
				r -= 1
				data[r] = apply(data[r], m, k)
				if k > 1:
					lazy[r] = comp(lazy[r], m)
			l >>= 1
			r >>= 1
			k <<= 1
		self._propagate_bottom_up()

	def get_interval(self, l, r):
		data = self.data
		op = self.op
		l += self.size
		r += self.size
		self._update_indices(l, self._l_indices)
		self._update_indices(r, self._r_indices)
		self._propagate_top_down()
		lx = self.op_e
		rx = self.op_e
		while l < r:
			if l & 1:
				lx = op(lx, data[l])
				l += 1
			if r & 1:
				r -= 1
				rx = op(data[r], rx)
			l >>= 1
			r >>= 1
		return op(lx, rx)
max2 = lambda x, y: x if x > y else y
min2 = lambda x, y: x if x < y else y
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
MOD = 998244353
(N, Q) = map(int, readline().split())
ones = [0] * N
v = 0
for i in range(N):
	ones[i] = v
	v = (v * 10 + 1) % MOD
power = [0] * N
v = 1
for i in range(N):
	power[i] = v
	v = v * 10 % MOD
W = 20
MASK = (1 << W) - 1

def compose(x, m):
	return x if m == 0 else m

def apply(x, m, l):
	return x if m == 0 else m * ones[l] % MOD << W | x & MASK

def op(a, b):
	return ((a >> W) + (b >> W) * power[b & MASK - a & MASK]) % MOD << W | a & MASK
seg = LazySegmentTree.from_initial_data(op, 0, compose, 0, apply, [1 << W | i for i in range(N)])
m = map(int, read().split())
for (l, r, d) in zip(m, m, m):
	(l, r) = (N - r, N - l)
	seg.update_interval(l, r + 1, d)
	print(seg.get_interval(0, N) >> 20)


(N, Q, *LRD) = [int(_) for _ in open(0).read().split()]
(L, R, D) = (LRD[::3], LRD[1::3], LRD[2::3])
mod = 998244353

class LazySegmentTree:
	__slots__ = ['n', 'data', 'lazy', 'me', 'oe', 'fmm', 'fmo', 'foo']

	def __init__(self, monoid_data, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator, func_operator_operator):
		self.me = monoid_identity
		self.oe = operator_identity
		self.fmm = func_monoid_monoid
		self.fmo = func_monoid_operator
		self.foo = func_operator_operator
		self.n = len(monoid_data)
		self.data = monoid_data * 2
		for i in range(self.n - 1, 0, -1):
			self.data[i] = self.fmm(self.data[2 * i], self.data[2 * i + 1])
		self.lazy = [self.oe] * (self.n * 2)

	def replace(self, index, value):
		index += self.n
		for shift in range(index.bit_length() - 1, 0, -1):
			i = index >> shift
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		self.data[index] = value
		self.lazy[index] = self.oe
		i = index
		while i > 1:
			i //= 2
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def effect(self, l, r, operator):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 //= 2
		while l0 > r0:
			indices.append(l0)
			l0 //= 2
		while l0 and l0 != r0:
			indices.append(r0)
			r0 //= 2
			if l0 == r0:
				break
			indices.append(l0)
			l0 //= 2
		while r0:
			indices.append(r0)
			r0 //= 2
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		while l < r:
			if l % 2:
				self.lazy[l] = self.foo(self.lazy[l], operator)
				l += 1
			if r % 2:
				r -= 1
				self.lazy[r] = self.foo(self.lazy[r], operator)
			l //= 2
			r //= 2
		for i in indices:
			self.data[i] = self.fmm(self.fmo(self.data[2 * i], self.lazy[2 * i]), self.fmo(self.data[2 * i + 1], self.lazy[2 * i + 1]))
			self.lazy[i] = self.oe

	def folded(self, l, r):
		l += self.n
		r += self.n
		indices = []
		l0 = l // (l & -l) // 2
		r0 = (r // (r & -r) - 1) // 2
		while r0 > l0:
			indices.append(r0)
			r0 //= 2
		while l0 > r0:
			indices.append(l0)
			l0 //= 2
		while l0 and l0 != r0:
			indices.append(r0)
			r0 //= 2
			if l0 == r0:
				break
			indices.append(l0)
			l0 //= 2
		while r0:
			indices.append(r0)
			r0 //= 2
		for i in reversed(indices):
			self.lazy[2 * i] = self.foo(self.lazy[2 * i], self.lazy[i])
			self.lazy[2 * i + 1] = self.foo(self.lazy[2 * i + 1], self.lazy[i])
			self.data[i] = self.fmo(self.data[i], self.lazy[i])
			self.lazy[i] = self.oe
		left_folded = self.me
		right_folded = self.me
		while l < r:
			if l % 2:
				left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
				l += 1
			if r % 2:
				r -= 1
				right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
			l //= 2
			r //= 2
		return self.fmm(left_folded, right_folded)
array = [(pow(10, i, mod), pow(10, i, mod)) for i in range(N)][::-1]
f = lambda a, b: ((a[0] + b[0]) % mod, (a[1] + b[1]) % mod)
g = lambda a, b: (b * a[1] % mod, a[1]) if b else a
h = lambda a, b: b if b else a
ti = (0, 0)
ei = 0
lst = LazySegmentTree(array, ti, ei, f, g, h)
ans = []
for (l, r, d) in zip(L, R, D):
	lst.effect(l - 1, r, d)
	ans += [lst.folded(0, N)[0]]
print('\n'.join(map(str, ans)))


import sys
input = sys.stdin.buffer.readline
MOD = 998244353
INF = 2 * 10 ** 18
in_n = lambda : int(input())
in_nn = lambda : map(int, input().split())
in_s = lambda : input().rstrip().decode('utf-8')
in_map = lambda : [s == ord('.') for s in input() if s != ord('\n')]
e = 0
id = -1
MASK = 32

def op(a, b):
	(a1, a2) = divmod(a, 1 << MASK)
	(b1, b2) = divmod(b, 1 << MASK)
	c1 = (a1 + b1) % MOD
	c2 = (a2 + b2) % MOD
	return (c1 << MASK) + c2

def mapping(x, a):
	if x == -1:
		return a
	(a1, a2) = divmod(a, 1 << MASK)
	c1 = x * a2 % MOD
	c2 = a2
	return (c1 << MASK) + c2

def composition(x, y):
	if x == -1:
		return y
	return x

class LazySegTree:

	def __init__(self, op, e, mapping, composition, id, n: int=-1, v: list=[]):
		assert (len(v) > 0) | (n > 0)
		if len(v) == 0:
			v = [e] * n
		self.__n = len(v)
		self.__log = (self.__n - 1).bit_length()
		self.__size = 1 << self.__log
		self.__d = [e] * (2 * self.__size)
		self.__lz = [id] * self.__size
		self.__op = op
		self.__e = e
		self.__mapping = mapping
		self.__composition = composition
		self.__id = id
		for i in range(self.__n):
			self.__d[self.__size + i] = v[i]
		for i in range(self.__size - 1, 0, -1):
			self.__update(i)

	def __update(self, k: int):
		self.__d[k] = self.__op(self.__d[2 * k], self.__d[2 * k + 1])

	def __all_apply(self, k: int, f):
		self.__d[k] = self.__mapping(f, self.__d[k])
		if k < self.__size:
			self.__lz[k] = self.__composition(f, self.__lz[k])

	def __push(self, k: int):
		self.__all_apply(2 * k, self.__lz[k])
		self.__all_apply(2 * k + 1, self.__lz[k])
		self.__lz[k] = self.__id

	def set(self, p: int, x):
		assert (0 <= p) & (p < self.__n)
		p += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(p >> i)
		self.__d[p] = x
		for i in range(1, self.__log + 1):
			self.__update(p >> i)

	def get(self, p: int):
		assert (0 <= p) & (p < self.__n)
		p += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(p >> i)
		return self.__d[p]

	def prod(self, l: int, r: int):
		assert (0 <= l) & (l <= r) & (r <= self.__n)
		if l == r:
			return self.__e
		l += self.__size
		r += self.__size
		for i in range(self.__log, 0, -1):
			if l >> i << i != l:
				self.__push(l >> i)
			if r >> i << i != r:
				self.__push(r >> i)
		sml = self.__e
		smr = self.__e
		while l < r:
			if l & 1:
				sml = self.__op(sml, self.__d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.__op(self.__d[r], smr)
			l //= 2
			r //= 2
		return self.__op(sml, smr)

	def all_prod(self):
		return self.__d[1]

	def apply(self, p: int, f):
		assert (0 <= p) & (p < self.__n)
		p += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(p >> i)
		self.__d[p] = self.__mapping(f, self.__d[p])
		for i in range(1, self.__log + 1):
			self.__update(p >> i)

	def apply_range(self, l: int, r: int, f):
		assert (0 <= l) & (l <= r) & (r <= self.__n)
		if l == r:
			return
		l += self.__size
		r += self.__size
		for i in range(self.__log, 0, -1):
			if l >> i << i != l:
				self.__push(l >> i)
			if r >> i << i != r:
				self.__push(r - 1 >> i)
		(l2, r2) = (l, r)
		while l < r:
			if l & 1:
				self.__all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.__all_apply(r, f)
			l //= 2
			r //= 2
		(l, r) = (l2, r2)
		for i in range(1, self.__log + 1):
			if l >> i << i != l:
				self.__update(l >> i)
			if r >> i << i != r:
				self.__update(r - 1 >> i)

	def max_right(self, l: int, g):
		assert (0 <= l) & (l <= self.__n)
		assert g(self.__e)
		if l == self.__n:
			return self.__n
		l += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(l >> i)
		sm = self.__e
		while True:
			while l % 2 == 0:
				l //= 2
			if not g(self.__op(sm, self.__d[l])):
				while l < self.__size:
					self.__push(l)
					l *= 2
					if g(self.__op(sm, self.__d[l])):
						sm = self.__op(sm, self.__d[l])
						l += 1
				return l - self.__size
			sm = self.__op(sm, self.__d[l])
			l += 1
			if l & -l == l:
				break
		return self.__n

	def min_left(self, r: int, g):
		assert (0 <= r) & (r <= self.__n)
		assert g(self.__e)
		if r == 0:
			return 0
		r += self.__size
		for i in range(self.__log, 0, -1):
			self.__push(r - 1 >> i)
		sm = self.__e
		while True:
			r -= 1
			while (r > 1) & r % 2:
				r //= 2
			if not g(self.__op(self.__d[r], sm)):
				while r < self.__size:
					self.__push(r)
					r = 2 * r + 1
					if g(self.__op(self.__d[r], sm)):
						sm = self.__op(self.__d[r], sm)
						r -= 1
				return r + 1 - self.__size
			sm = self.__op(self.__d[r], sm)
			if r & -r == r:
				break
		return 0

	def all_push(self):
		for i in range(1, self.__size):
			self.__push(i)

	def get_all(self):
		self.all_push()
		return self.__d[self.__size:self.__size + self.__n]

	def print(self):
		print(list(map(lambda x: divmod(x, 1 << 30), self.__d)))
		print(self.__lz)
		print('------------------')

def main():
	(N, Q) = in_nn()
	A = [0] * N
	tmp = 1
	for i in range(N - 1, -1, -1):
		A[i] = (tmp << MASK) + tmp
		tmp *= 10
		tmp %= MOD
	seg = LazySegTree(op, e, mapping, composition, id, v=A)
	ans = [0] * Q
	for i in range(Q):
		(l, r, d) = in_nn()
		l -= 1
		seg.apply_range(l, r, d)
		ans[i] = seg.all_prod() >> MASK
	print('\n'.join(map(str, ans)))
main()


import sys
input = sys.stdin.readline
(N, Q) = map(int, input().split())
mod = 998244353
seg_el = 1 << N.bit_length()
seg_height = 1 + N.bit_length()
SEG = [0 for i in range(2 * seg_el)]
LAZY = [0 for i in range(2 * seg_el)]
POW10 = [1]
for i in range(N + 1):
	POW10.append(POW10[-1] * 10 % mod)
gyaku = pow(9, mod - 2, mod)

def seg_function(x, y):
	return (x + y) % mod
for i in range(N):
	SEG[i + seg_el] = POW10[i]
for i in range(seg_el - 1, 0, -1):
	SEG[i] = seg_function(SEG[i * 2], SEG[i * 2 + 1])

def lazy_change(ind, b):
	kousuu = 1 << seg_height - ind.bit_length()
	tyousei = (ind - (1 << ind.bit_length() - 1)) * kousuu
	SEG[ind] = POW10[tyousei] * b * (POW10[kousuu] - 1) % mod * gyaku % mod

def lazy_compose(ind, b):
	LAZY[ind] = b

def indexes(L, R):
	INDLIST = []
	R -= 1
	L >>= 1
	R >>= 1
	while L != R:
		if L > R:
			INDLIST.append(L)
			L >>= 1
		else:
			INDLIST.append(R)
			R >>= 1
	while L != 0:
		INDLIST.append(L)
		L >>= 1
	return INDLIST

def changes(l, r, b0):
	L = l + seg_el
	R = r + seg_el
	L //= L & -L
	R //= R & -R
	UPIND = indexes(L, R)
	for ind in UPIND[::-1]:
		if LAZY[ind] != 0:
			b = LAZY[ind]
			lazy_change(ind << 1, b)
			lazy_change(1 + (ind << 1), b)
			lazy_compose(ind << 1, b)
			lazy_compose(1 + (ind << 1), b)
			LAZY[ind] = 0
	while L != R:
		if L > R:
			lazy_change(L, b0)
			lazy_compose(L, b0)
			L += 1
			L //= L & -L
		else:
			R -= 1
			lazy_change(R, b0)
			lazy_compose(R, b0)
			R //= R & -R
	for ind in UPIND:
		SEG[ind] = seg_function(SEG[ind << 1], SEG[1 + (ind << 1)])
for qu in range(Q):
	(L, R, D) = map(int, input().split())
	(L, R) = (N - R + 1, N - L + 1)
	changes(L - 1, R, D)
	sys.stdout.write(str(SEG[1]) + '\n')


class LazySegmentTree:
	__slots__ = ['merge', 'merge_unit', 'operate', 'merge_operate', 'operate_unit', 'n', 'data', 'lazy']

	def __init__(self, n, init, merge, merge_unit, operate, merge_operate, operate_unit):
		self.merge = merge
		self.merge_unit = merge_unit
		self.operate = operate
		self.merge_operate = merge_operate
		self.operate_unit = operate_unit
		self.n = (n - 1).bit_length()
		self.data = [merge_unit for i in range(1 << self.n + 1)]
		self.lazy = [operate_unit for i in range(1 << self.n + 1)]
		if init:
			for i in range(n):
				self.data[2 ** self.n + i] = init[i]
			for i in range(2 ** self.n - 1, 0, -1):
				self.data[i] = self.merge(self.data[2 * i], self.data[2 * i + 1])

	def propagate(self, v):
		ope = self.lazy[v]
		if ope == self.operate_unit:
			return
		self.lazy[v] = self.operate_unit
		self.data[v << 1] = self.operate(self.data[v << 1], ope)
		self.data[(v << 1) + 1] = self.operate(self.data[(v << 1) + 1], ope)
		self.lazy[v << 1] = self.merge_operate(self.lazy[v << 1], ope)
		self.lazy[(v << 1) + 1] = self.merge_operate(self.lazy[(v << 1) + 1], ope)

	def propagate_above(self, i):
		m = i.bit_length() - 1
		for bit in range(m, 0, -1):
			v = i >> bit
			self.propagate(v)

	def remerge_above(self, i):
		while i:
			c = self.merge(self.data[i], self.data[i ^ 1])
			i >>= 1
			self.data[i] = self.operate(c, self.lazy[i])

	def update(self, l, r, x):
		l += 1 << self.n
		r += 1 << self.n
		l0 = l // (l & -l)
		r0 = r // (r & -r) - 1
		self.propagate_above(l0)
		self.propagate_above(r0)
		while l < r:
			if l & 1:
				self.data[l] = self.operate(self.data[l], x)
				self.lazy[l] = self.merge_operate(self.lazy[l], x)
				l += 1
			if r & 1:
				self.data[r - 1] = self.operate(self.data[r - 1], x)
				self.lazy[r - 1] = self.merge_operate(self.lazy[r - 1], x)
			l >>= 1
			r >>= 1
		self.remerge_above(l0)
		self.remerge_above(r0)

	def query(self, l, r):
		l += 1 << self.n
		r += 1 << self.n
		l0 = l // (l & -l)
		r0 = r // (r & -r) - 1
		self.propagate_above(l0)
		self.propagate_above(r0)
		res = self.merge_unit
		while l < r:
			if l & 1:
				res = self.merge(res, self.data[l])
				l += 1
			if r & 1:
				res = self.merge(res, self.data[r - 1])
			l >>= 1
			r >>= 1
		return res

	def bisect_l(self, l, r, x):
		l += 1 << self.n
		r += 1 << self.n
		l0 = l // (l & -l)
		r0 = r // (r & -r) - 1
		self.propagate_above(l0)
		self.propagate_above(r0)
		Lmin = -1
		Rmin = -1
		while l < r:
			if l & 1:
				if self.data[l][0] <= x and Lmin == -1:
					Lmin = l
				l += 1
			if r & 1:
				if self.data[r - 1][0] <= x:
					Rmin = r - 1
			l >>= 1
			r >>= 1
		res = -1
		if Lmin != -1:
			pos = Lmin
			while pos < self.num:
				self.propagate(pos)
				if self.data[2 * pos][0] <= x:
					pos = 2 * pos
				else:
					pos = 2 * pos + 1
			res = pos - self.num
		if Rmin != -1:
			pos = Rmin
			while pos < self.num:
				self.propagate(pos)
				if self.data[2 * pos][0] <= x:
					pos = 2 * pos
				else:
					pos = 2 * pos + 1
			if res == -1:
				res = pos - self.num
			else:
				res = min(res, pos - self.num)
		return res
mod = 998244353
mask = 2 ** 32 - 1

def merge(x, y):
	(val_x, base_x) = (x >> 32, x & mask)
	(val_y, base_y) = (y >> 32, y & mask)
	res_val = (val_x + val_y) % mod
	res_base = (base_x + base_y) % mod
	res = (res_val << 32) + res_base
	return res
merge_unit = 0

def operate(x, y):
	if y == 0:
		return x
	(val, base) = (x >> 32, x & mask)
	val = base * y % mod
	x = (val << 32) + base
	return x

def merge_operate(x, y):
	return y
operate_unit = 0
import sys
input = sys.stdin.readline
(N, Q) = map(int, input().split())
init = [(pow(10, N - 1 - i, mod) << 32) + pow(10, N - 1 - i, mod) for i in range(N)]
LST = LazySegmentTree(N, init, merge, merge_unit, operate, merge_operate, operate_unit)
for i in range(Q):
	(l, r, d) = map(int, input().split())
	LST.update(l - 1, r, d)
	print(LST.query(0, N) >> 32)


class lazy_segtree:

	def __init__(self, V, OP, E, MAPPING, COMPOSITION, ID):
		self.n = len(V)
		self.log = (self.n - 1).bit_length()
		self.size = 1 << self.log
		self.d = [E for i in range(2 * self.size)]
		self.lz = [ID for i in range(self.size)]
		self.e = E
		self.op = OP
		self.mapping = MAPPING
		self.composition = COMPOSITION
		self.identity = ID
		for i in range(self.n):
			self.d[self.size + i] = V[i]
		for i in range(self.size - 1, 0, -1):
			self.update(i)

	def set(self, p, x):
		assert 0 <= p and p < self.n
		p += self.size
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		self.d[p] = x
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def get(self, p):
		assert 0 <= p and p < self.n
		p += self.size
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		return self.d[p]

	def prod(self, l, r):
		assert 0 <= l and l <= r and (r <= self.n)
		if l == r:
			return self.e
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r >> i)
		(sml, smr) = (self.e, self.e)
		while l < r:
			if l & 1:
				sml = self.op(sml, self.d[l])
				l += 1
			if r & 1:
				r -= 1
				smr = self.op(self.d[r], smr)
			l >>= 1
			r >>= 1
		return self.op(sml, smr)

	def all_prod(self):
		return self.d[1]

	def apply(self, p, f):
		assert 0 <= p and p < self.n
		p += self.size
		for i in range(self.log, 0, -1):
			self.push(p >> i)
		self.d[p] = self.mapping(f, self.d[p])
		for i in range(1, self.log + 1):
			self.update(p >> i)

	def apply(self, l, r, f):
		assert 0 <= l and l <= r and (r <= self.n)
		if l == r:
			return
		l += self.size
		r += self.size
		for i in range(self.log, 0, -1):
			if l >> i << i != l:
				self.push(l >> i)
			if r >> i << i != r:
				self.push(r - 1 >> i)
		(l2, r2) = (l, r)
		while l < r:
			if l & 1:
				self.all_apply(l, f)
				l += 1
			if r & 1:
				r -= 1
				self.all_apply(r, f)
			l >>= 1
			r >>= 1
		(l, r) = (l2, r2)
		for i in range(1, self.log + 1):
			if l >> i << i != l:
				self.update(l >> i)
			if r >> i << i != r:
				self.update(r - 1 >> i)

	def max_right(self, l, g):
		assert 0 <= l and l <= self.n
		assert g(self.e)
		if l == self.n:
			return self.n
		l += self.size
		for i in range(self.log, 0, -1):
			self.push(l >> i)
		sm = self.e
		while 1:
			while i % 2 == 0:
				l >>= 1
			if not g(self.op(sm, self.d[l])):
				while l < self.size:
					self.push(l)
					l = 2 * l
					if g(self.op(sm, self.d[l])):
						sm = self.op(sm, self.d[l])
						l += 1
				return l - self.size
			sm = self.op(sm, self.d[l])
			l += 1
			if l & -l == l:
				break
		return self.n

	def min_left(self, r, g):
		assert 0 <= r and r <= self.n
		assert g(self.e)
		if r == 0:
			return 0
		r += self.size
		for i in range(self.log, 0, -1):
			self.push(r - 1 >> i)
		sm = self.e
		while 1:
			r -= 1
			while r > 1 and r % 2:
				r >>= 1
			if not g(self.op(self.d[r], sm)):
				while r < self.size:
					self.push(r)
					r = 2 * r + 1
					if g(self.op(self.d[r], sm)):
						sm = self.op(self.d[r], sm)
						r -= 1
				return r + 1 - self.size
			sm = self.op(self.d[r], sm)
			if r & -r == r:
				break
		return 0

	def update(self, k):
		self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])

	def all_apply(self, k, f):
		self.d[k] = self.mapping(f, self.d[k])
		if k < self.size:
			self.lz[k] = self.composition(f, self.lz[k])

	def push(self, k):
		self.all_apply(2 * k, self.lz[k])
		self.all_apply(2 * k + 1, self.lz[k])
		self.lz[k] = self.identity
import sys
input = sys.stdin.readline
(N, Q) = map(int, input().split())
mod = 998244353
inv9 = pow(9, mod - 2, mod)
pow10 = [0 for i in range(N + 1)]
pow10[0] = 1
for i in range(N):
	pow10[i + 1] = 10 * pow10[i] % mod

def operate(a, b):
	(a0, a1) = (a >> 32, a % (1 << 32))
	(b0, b1) = (b >> 32, b % (1 << 32))
	x0 = (a0 * pow10[b1] + b0) % mod
	x1 = a1 + b1
	return (x0 << 32) + x1

def mapping(f, x):
	(f0, f1) = (f >> 32, f % (1 << 32))
	(x0, x1) = (x >> 32, x % (1 << 32))
	y0 = (f0 * x0 + f1 * inv9 * (pow10[x1] - 1)) % mod
	y1 = x1
	return (y0 << 32) + y1

def composition(f, g):
	(f0, f1) = (f >> 32, f % (1 << 32))
	(g0, g1) = (g >> 32, g % (1 << 32))
	return (f0 * g0 % mod << 32) + (g1 * f0 + f1) % mod
G = lazy_segtree([(1 << 32) + 1 for i in range(N)], operate, 0, mapping, composition, 1 << 32)
for i in range(Q):
	(l, r, d) = map(int, input().split())
	l -= 1
	G.apply(l, r, d)
	print(G.all_prod() >> 32)


import sys
input = sys.stdin.readline
mod = 998244353
(n, q) = map(int, input().split())

class LazySegTree:

	def __init__(self, N):
		self.INF = 2 ** 31 - 1
		self.N = N
		self.LV = (self.N - 1).bit_length()
		self.N0 = 2 ** self.LV
		self.data = [0] * (2 * self.N0)
		self.lazy = [0] * (2 * self.N0)
		self.size = [0] * (2 * self.N0)
		val = 1
		for i in range(self.N):
			self.size[self.N0 + self.N - 2 - i] = val
			val = val * 10 % mod
		for i in range(self.N0 - 2, -1, -1):
			self.size[i] = (self.size[2 * i + 1] + self.size[2 * i + 2]) % mod

	def gindex(self, l, r):
		L = l + self.N0 >> 1
		R = r + self.N0 >> 1
		lc = 0 if l & 1 else (L & -L).bit_length()
		rc = 0 if r & 1 else (R & -R).bit_length()
		for i in range(self.LV):
			if rc <= i:
				yield R
			if L < R and lc <= i:
				yield L
			L >>= 1
			R >>= 1

	def propagates(self, *ids):
		for i in reversed(ids):
			v = self.lazy[i - 1]
			if not v:
				continue
			self.lazy[2 * i - 1] = v
			self.lazy[2 * i] = v
			self.data[2 * i - 1] = v * self.size[2 * i - 1] % mod
			self.data[2 * i] = v * self.size[2 * i] % mod
			self.lazy[i - 1] = 0

	def update(self, l, r, x):
		(*ids,) = self.gindex(l, r)
		self.propagates(*ids)
		L = self.N0 + l
		R = self.N0 + r
		while L < R:
			if R & 1:
				R -= 1
				self.lazy[R - 1] = x
				self.data[R - 1] = x * self.size[R - 1] % mod
			if L & 1:
				self.lazy[L - 1] = x
				self.data[L - 1] = x * self.size[L - 1] % mod
				L += 1
			L >>= 1
			R >>= 1
		for i in ids:
			self.data[i - 1] = (self.data[2 * i - 1] + self.data[2 * i]) % mod

	def query(self, l, r):
		self.propagates(*self.gindex(l, r))
		L = self.N0 + l
		R = self.N0 + r
		s = 0
		while L < R:
			if R & 1:
				R -= 1
				s = (s + self.data[R - 1]) % mod
			if L & 1:
				s = (s + self.data[L - 1]) % mod
				L += 1
			L >>= 1
			R >>= 1
		return s
lst = LazySegTree(n)
lst.update(0, n, 1)
for _ in range(q):
	(l, r, d) = map(int, input().split())
	l -= 1
	lst.update(l, r, d)
	print(lst.query(0, n))