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

#define rep(i,n) for(i = 0;i < n;++i)
#define all(v) v.begin(), v.end()
using ll = long long;

ll pow_mod(ll a, ll n, ll p)
{
    ll res = 1;
    while(n > 0){
        if(n & 1) res = res*a%p;
        a = a*a%p;
        n >>= 1;
    }
    return res;
}

const ll MOD = 998244353;

template <typename T>
struct SegmentTreeLazy //デフォルトは区間変更区間合計
{
    int n;
    const T ex = 0; //dat 初期値(合計なので)
    const T em = 1ll << 60; //lazy 初期値(updateするので)
    //lazyで一括更新をもって、datでqueryに対応する。weightはそのnodeが担当する下のnodeの数
    //lazyは上から下に伝搬する。datは区間で探して下から上にもらう。
    vector<T> dat, lazy, weight; //tree本体
    SegmentTreeLazy(vector<T> v){
        int x = 1;
        int i;
        n = v.size();
        while(x < n) x <<= 1;
        n = x; 
        dat.resize(2*n-1, ex); //tree本体
        lazy.resize(2*n-1, em); //遅延評価
        weight.resize(2*n-1, 0); //何node持ってるか
        for(i = 0;i < v.size();++i){
            weight.at(i + n - 1) = pow_mod(10, v.size()-1-i,MOD);
            dat.at(i + n - 1) = v.at(i)*weight.at(i + n - 1)%MOD;
        }
        for(i = n-2;i >= 0;--i){
            dat.at(i) = fx(dat.at(2*i+1), dat.at(2*i+2));
            weight.at(i) = (weight.at(2*i + 1) + weight.at(2*i + 2))%MOD;
        }
    }
    
    T fx(T a, T b){ //dat上での計算
        return (a + b)%MOD; //区間加算なので加算
    }
    
    T fm(T a){ //lazy上での計算
        return min(a, em);
    }
    
    void eval(int now){ //区間下は全て影響を受ける。(受ける時しか呼ばれない)
        if(lazy.at(now) == em) return;
        if(now < n - 1){ //区間変更なので値を代入する。
            lazy.at(2*now + 1) = fm(lazy.at(now));
            lazy.at(2*now + 2) = fm(lazy.at(now));
        }
        //**********************ここが大事
        dat.at(now) = lazy.at(now)*weight.at(now); //区間加算する。
        //**********************
        lazy.at(now) = em;
    }
    
    void update(int a, int b, T x, int now, int l, int r){
        eval(now);
        if(a <= l && r<= b){ //区間内に全部いる。

            lazy.at(now) = x; //区間代入なので上から書き換える。

            eval(now);
        }else if(a < r && l < b){
            update(a, b, x, 2*now + 1, l, (l + r)/2);
            update(a, b, x, 2*now + 2, (l + r)/2, r);
            dat.at(now) = fx(dat.at(2*now + 1), dat.at(2*now + 2));
        }
    }
    void update(int a, int b, T x){update(a, b, x, 0, 0, n);}
    
    T query(int a, int b){return query_sub(a, b, 0, 0, n);}
    T query_sub(int a, int b, int now, int l, int r){
        eval(now);
        if(r <= a || b <= l) return ex;
        else if(a <= l && r <= b) return dat.at(now);
        else{
            T vl = query_sub(a, b, 2*now + 1, l, (l + r)/2);
            T vr = query_sub(a, b, 2*now + 2, (l + r)/2, r);
            return fx(vl, vr);
        }
    }
    
    inline T operator[](int a) { return query(a, a + 1); }
    void print() {
        for (int i = 0; i < 2 * n - 1; ++i) {
            cout << (*this)[i];
            if (i != n) cout << "," << endl;
            if(i == n) cout << endl;
        }
        cout << endl;
    }
};

int main()
{
    ll i,j;
    ll n,q;
    cin >> n >> q;
    vector<ll> a(n, 1);
    SegmentTreeLazy<ll> seg(a);
    rep(i,q){
        ll l,r,d;
        cin >> l >> r >> d;
        --l;
        seg.update(l, r, d);
        cout << seg.query(0, n) << endl;
    }

    return 0;
}

Measured memory_bytes: 18584