#include <bits/stdc++.h>
using namespace std;

const int64_t MOD = 998244353;
void add(int64_t& a, int64_t b){
    a = (a+b) % MOD;
}
void mul(int64_t& a, int64_t b){
    a = a*b % MOD;
}

template<typename F, typename T, typename Func_mf, typename Func_op, typename Func_mv>
struct LazySegtree {
    int n, n_org;
    vector<T> dat;
    vector<F> laz;
    Func_mf merge_functions;
    Func_op operate;
    Func_mv merge_values;
    F fe;
    T te;

    LazySegtree(){}
    LazySegtree(int n_org,
                Func_mf merge_functions,
                Func_op operate,
                Func_mv merge_values,
                F fe, T te):
                n_org(n_org),
                merge_functions(merge_functions),
                operate(operate),
                merge_values(merge_values),
                fe(fe), te(te){
        n = 1;
        while(n < n_org) n <<= 1;
        dat.assign(2*n-1, te);
        laz.assign(2*n-1, fe);
    }

    void build(vector<T>& A){
        for(int k=0; k<int(A.size()); k++) dat[k+n-1] = A[k];
        for(int k=n-2; k>=0; k--) dat[k] = merge_values(dat[2*k+1], dat[2*k+2]);
    }

    void eval(int k, int lb, int rb){
        if(laz[k] == fe) return;
        operate(dat[k], laz[k], lb, rb);
        if(k < n-1){
            merge_functions(laz[2*k+1], laz[k]);
            merge_functions(laz[2*k+2], laz[k]);
        }
        laz[k] = fe;
    }

    void update_between(int a, int b, F x){
        update(a, b+1, x, 0, 0, n);
    }

    void update(int a, int b, F x, int k, int lb, int rb){
        eval(k, lb, rb);
        if(b <= lb || rb <= a) return;
        if(a <= lb && rb <= b){
            merge_functions(laz[k], x);
            eval(k, lb, rb);
        }else{
            int mb = (lb+rb)>>1;
            update(a, b, x, 2*k+1, lb, mb);
            update(a, b, x, 2*k+2, mb, rb);
            dat[k] = merge_values(dat[2*k+1], dat[2*k+2]);
        }
    }

    T get_between(int a, int b){
        return query(a, b+1, 0, 0, n);
    }

    T query(int a, int b, int k, int lb, int rb){
        eval(k, lb, rb);
        if(rb<=a || b<=lb) return te;
        if(a<=lb && rb<=b) return dat[k];
        int mb = (lb+rb)>>1;
        T vl = query(a, b, 2*k+1, lb, mb);
        T vr = query(a, b, 2*k+2, mb, rb);
        return merge_values(vl, vr);
	}
};

vector<int64_t> p10, p10s;

auto make_segtree = [](int N){
    using F = int;
    using T = int64_t;
    F fe = 0;
    T te = 0;
    auto merge_functions = [&](F& f, F& g){
        if(g) f = g;
    };
    auto operate = [&](T& v, F& f, int l, int r){
        if(f) v = f * (p10s[r] - p10s[l] + MOD) % MOD;
    };
    auto merge_values = [](T& a, T& b){
        return (a+b) % MOD;
    };
    return LazySegtree<F, T, decltype(merge_functions), decltype(operate), decltype(merge_values)>
        (N, merge_functions, operate, merge_values, fe, te);
};
 
int main(){
	int N, Q;
	cin >> N >> Q;
	p10.resize(N, 1);
	p10s.resize(N+1);
	for(int i=N-2; i>=0; i--) p10[i] = p10[i+1] * 10 % MOD;
	for(int i=0; i<N; i++) p10s[i+1] = (p10[i] + p10s[i]) % MOD; 
	auto st = make_segtree(N);
	st.build(p10);
	while(Q--){
		int l, r, d;
		cin >> l >> r >> d;
		st.update_between(l-1, r-1, d);
		cout << st.get_between(0, N-1) << endl;
	}
}


Measured memory_bytes: 12372