### BUGGY CODE ###

def numba_compile(numba_config):
    import os, sys
    if sys.argv[-1] == "ONLINE_JUDGE":
        from numba import njit
        from numba.pycc import CC
        cc = CC("my_module")
        for func, signature in numba_config:
            globals()[func.__name__] = njit(signature)(func)
            cc.export(func.__name__, signature)(func)
        cc.compile()
        exit()
    elif os.name == "posix":
        exec(f"from my_module import {','.join(func.__name__ for func, _ in numba_config)}")
        for func, _ in numba_config:
            globals()[func.__name__] = vars()[func.__name__]
    else:
        from numba import njit
        for func, signature in numba_config:
            globals()[func.__name__] = njit(signature, cache=True)(func)
        print("compiled!", file=sys.stderr)


import sys
import numpy as np


def solve(N, Q, LRD):
    mod = 998244353
    p = 1
    n = 0
    p10 = np.empty(202020, dtype=np.int64)
    n11 = np.empty(202020, dtype=np.int64)
    for i in range(202020):
        p10[i] = p
        n11[i] = n
        p = p*10%mod
        n = (n*10+1)%mod

    identity = 0
    sqrtN = 128
    n_buckets = N//sqrtN+1
    Data_val = np.ones(n_buckets*sqrtN, dtype=np.int64)
    Data_val[N:] = 0
    Bucket_val = np.full(n_buckets, n11[sqrtN], dtype=np.int64)
    Lazy = np.full(n_buckets, identity, dtype=np.int64)
    M = N % sqrtN
    Bucket_val[n_buckets-1] = n11[M]

    def eval_data(k):
        if Lazy[k] != identity:
            l, r = k*sqrtN, (k+1)*sqrtN
            for i in range(l, r):
                Data_val[i] = Lazy[k]
            Lazy[k] = identity

    def apply(s, t, f):
        for k in range(s//sqrtN, (t-1)//sqrtN+1):
            l, r = k*sqrtN, (k+1)*sqrtN
            if s <= l and r <= t:
                Bucket_val[k] = f * n11[sqrtN] % mod
                Lazy[k] = f
            else:
                eval_data(k)
                for i in range(max(l, s), min(r, t)):
                    Data_val[i] = f
                Bucket_val[k] = 0
                for i in range(l, min(r, N)):
                    Bucket_val[k] = (Bucket_val[k] * 10 + Data_val[i]) % mod

    def get(i):
        k = i//sqrtN
        eval_data(k)
        return Data_val[i]

    def all_prod():
        res = 0
        for k in range(n_buckets-1):
            res = (res * p10[sqrtN] + Bucket_val[k]) % mod
        res = (res * p10[M] + Bucket_val[n_buckets-1]) % mod
        return res

    Ans = np.zeros(Q, dtype=np.int64)
    for i in range(Q):
        l, r, d = LRD[i]
        apply(l-1, r, d)
        ans = all_prod()
        Ans[i] = ans

    return Ans


numba_compile([
    [solve, "i8[:](i8,i8,i8[:,:])"]
])


def main():
    N, Q = map(int, sys.stdin.buffer.readline().split())
    LRD = np.array(sys.stdin.buffer.read().split(), dtype=np.int64).reshape(Q, 3)
    Ans = solve(N, Q, LRD)
    print("\n".join(map(str, Ans.tolist())))


main()


### FIXED CODE ###

class LazySegmentTree:  # from https://atcoder.jp/contests/practice2/submissions/16598122
    __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

        # propagation
        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

        # update
        self.data[index] = value
        self.lazy[index] = self.oe

        # recalculation
        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

        # preparing indices
        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

        # propagation
        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

        # effect
        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

        # recalculation
        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

        # preparing indices
        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

        # propagation
        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

        # fold
        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 = LazySegTree(op, e, mapping, aaa, i, [(1, 1) for _ in range(N)])
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.apply(l-1, r, d)
    seg.effect(l-1, r, d)
    #ans = seg.all_prod()[0]
    ans = seg.folded(0, N)[0]
    Ans.append(ans)
print("\n".join(map(str, Ans)))