#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
#define REP(i, n) for (int i = 0, i##_len = (n); i < i##_len; ++i)
#define FOR(i, a, b) for (int i = (a), i##_len = (b); i < i##_len; i++)
#define ALL(x) (x).begin(), (x).end()  // sortなどの引数を省略したい
#ifdef _DEBUG
#define PRE_COMMAND             \
    std::cin.rdbuf(in.rdbuf()); \
    std::cout << fixed << setprecision(15);
#else
#define PRE_COMMAND cout << fixed << setprecision(15);
#endif
const double EPS = 1e-10, PI = acos(-1.0);
template <class T> auto MAX(T& seq) {
    return *max_element(seq.begin(), seq.end());
}
template <class T> auto MIN(T& seq) {
    return *min_element(seq.begin(), seq.end());
}
template <class T> auto SUM(T& seq) {
    T temp{0};
    auto& temp2 = temp[0];
    return accumulate(seq.begin(), seq.end(), temp2);
}
template <class T> void SORT(T& seq) { sort(seq.begin(), seq.end()); }
template <class T, class S> void SORT(T& seq, S& sort_order) {
    sort(seq.begin(), seq.end(), sort_order);
}
template <class T> void SORTR(vector<T>& seq) {
    sort(seq.begin(), seq.end(), greater<T>());
}
template <class T, class S, class R> long long pow(T n_0, S k_0, R mod_0) {
    long long n = n_0 % mod_0, k = k_0, mod = mod_0, now = 1;
    while (k) {
        if (k & 1) now = (now * n) % mod;
        n = (n * n) % mod;
        k >>= 1;
    }
    return now;
}
template <typename T> istream& operator>>(istream& is, vector<T>& vec) {
    for (T& x : vec) is >> x;
    return is;
}

template <long long mod> struct modint {
    long long val;
    // _mod < 2^31である必要あり
    // _modが素数でないときは割り算ができない
    modint() {}
    template <class T> modint(T v) : val(v) {
        if (abs(val) >= mod) val %= mod;
        if (val < 0) val += mod;
    }
    // 単項演算子++の定義
    modint& operator++() {
        val++;
        if (val == mod) val = 0;
        return *this;
    }
    // 単項演算子--の定義
    modint& operator--() {
        if (val == 0) val = mod;
        val--;
        return *this;
    }
    // 二項演算子++の定義
    modint operator++(int) {
        modint result = *this;
        ++*this;
        return result;
    }
    // 二項演算子--の定義
    modint operator--(int) {
        modint result = *this;
        --*this;
        return result;
    }
    // +=の定義
    modint& operator+=(const modint& rhs) {
        val += rhs.val;
        if (val >= mod) val -= mod;
        return *this;
    }
    // -=の定義
    modint& operator-=(const modint& rhs) {
        val -= rhs.val;
        if (val < 0) val += mod;
        return *this;
    }
    // *=の定義
    modint& operator*=(const modint& rhs) {
        val *= rhs.val;
        if (abs(val) >= mod) val %= mod;
        if (val < 0) val += mod;
        return *this;
    }
    // /=の定義
    modint& operator/=(const modint& rhs) { return *this = *this * rhs.inv(); }
    // 単項演算子+の定義
    modint operator+() const { return *this; }
    // 単項演算子-の定義
    modint operator-() const { return modint(-val); }
    // 二項演算子+の定義
    friend modint operator+(const modint& lhs, const modint& rhs) {
        return modint(lhs.val) += rhs;
    }
    // 二項演算子-の定義
    friend modint operator-(const modint& lhs, const modint& rhs) {
        return modint(lhs.val) -= rhs;
    }
    // 二項演算子*の定義
    friend modint operator*(const modint& lhs, const modint& rhs) {
        return modint(lhs.val) *= rhs;
    }
    // 二項演算子/の定義
    friend modint operator/(const modint& lhs, const modint& rhs) {
        return modint(lhs.val) /= rhs;
    }
    // 二項演算子==の定義
    friend bool operator==(const modint& lhs, const modint& rhs) {
        return lhs.val == rhs.val;
    }
    // 二項演算子!=の定義
    friend bool operator!=(const modint& lhs, const modint& rhs) {
        return lhs.val != rhs.val;
    }
    // powの定義、使う演算子は既にmodint内で定義しているのでintのときと同様でOK
    modint pow_mod(long long n) const {
        long long x = val, r = 1;
        while (n) {
            if (n & 1) r *= x;
            if (r >= mod) r %= mod;
            x *= x;
            if (x >= mod) x %= mod;
            n >>= 1;
        }
        return modint(r, mod);
    }
    // 逆元を出力
    modint inv() const {
        long long x = val, r = 1, n = mod - 2;
        while (n) {
            if (n & 1) r *= x;
            if (r >= mod) r %= mod;
            x *= x;
            if (x >= mod) x %= mod;
            n >>= 1;
        }
        return modint(r, mod);
    }
};

//除数の設定
static const long long mod = 998244353;
using mint = modint<mod>;

//入出力ストリーム
istream& operator>>(istream& is, mint& x) {  // xにconst付けない
    ll t;
    is >> t;
    x = t;
    return (is);
}
ostream& operator<<(ostream& os, const mint& x) { return os << x.val; }

template <class S, S (*op)(S, S), class F, S (*mapping)(F, S),
          F (*composition)(F, F)>
struct lazy_segtree {
    int basesize, num, depth = 0;
    std::vector<S> d;
    std::vector<F> lz;
    S e;
    F id;
    // 元の配列, op, e, mapping, composition, id
    lazy_segtree(const std::vector<S>& base, S tmp1, F tmp2)
        : basesize(int(base.size())), e(tmp1), id(tmp2) {
        while ((1 << depth) < basesize) depth++;
        num = 1 << depth;
        d = std::vector<S>(num << 1, e);
        lz = std::vector<F>(num, id);
        for (int i = 0; i < basesize; i++) d[num + i] = base[i];
        for (int i = num - 1; i >= 1; i--) update(i);
    }
    // 頂点kについて、dを下から計算しなおす（上方向に更新）
    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    // 頂点kについて、dとlzにそれぞれfを作用させる
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < num) lz[k] = composition(f, lz[k]);
    }
    // 頂点kについて、lzの中身を一つ下に伝搬させ、lzを単位元にする
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id;
    }
    // 配列の位置pの値をxにして、根まで順番に上に伝播させる
    void set(int p, S x) {
        assert(0 <= p && p < basesize);
        p += num;
        for (int i = depth; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= depth; i++) update(p >> i);
    }
    // 配列の位置pの値を取得する
    S get(int p) {
        assert(0 <= p && p < basesize);
        p += num;
        // 根から順番にpush
        for (int i = depth; i >= 1; i--) push(p >> i);
        // 伝播が終わったので出力
        return d[p];
    }
    // 配列の[l, r)の区間積を取得する
    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= basesize);
        // 区間サイズが0なら単位元を出力
        if (l == r) return e;
        l += num, r += num;
        // 区間の大きい方から見て行って、lやrが区間の左端でなければpushして伝播
        for (int i = depth; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push(r >> i);
        }
        S sml = e, smr = e;
        // 既に必要箇所の伝播が終わっているので、下から順番にopでマージしていく
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1, r >>= 1;
        }
        return op(sml, smr);
    }
    // 全区間の積を出力
    S all_prod() { return d[1]; }
    // 配列の位置pにfを作用させる
    void apply(int p, F f) {
        assert(0 <= p && p < basesize);
        p += num;
        // 上から順番にpushで伝播
        for (int i = depth; i >= 1; i--) push(p >> i);
        // pにfを作用させる（d[p]に直接作用させる）
        d[p] = mapping(f, d[p]);
        // 上方向に向かって更新する
        for (int i = 1; i <= depth; i++) update(p >> i);
    }
    // [l, r)にfを作用させる
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= basesize);
        // 区間サイズが0のときは何もしない
        if (l == r) return;
        l += num, r += num;
        for (int i = depth; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            // ACLではupdate((r - 1) >> i)になっているが、同じなはず
            if (((r >> i) << i) != r) push(r >> i);
        }
        int l2 = l, r2 = r;
        while (l < r) {
            // 必要な箇所に下からfを作用させていく
            if (l & 1) all_apply(l++, f);
            if (r & 1) all_apply(--r, f);
            l >>= 1, r >>= 1;
        }
        l = l2, r = r2;
        // 上方向に向かって更新する
        for (int i = 1; i <= depth; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            // ACLではupdate((r - 1) >> i)になっているが、同じなはず
            if (((r >> i) << i) != r) update(r >> i);
        }
    }
    template <bool (*g)(S)> int max_right(int l) {
        assert(0 <= l && l <= basesize);
        assert(g(e));
        if (l == basesize) return basesize;
        l += num;
        // 必要な部分について伝播を行っておく
        for (int i = depth; i >= 1; i--) push(l >> i);
        S sm = e;
        // 1が立っているbitが1つになるまで、
        // つまり配列を右端まで探索し終わるまで繰り返す
        do {
            // lを含む区間が右側に来るまで上る
            while (!(l & 1)) l >>= 1;
            // もしダメだったら下に検索していく
            if (!g(op(sm, d[l]))) {
                while (l < num) {
                    push(l);
                    l <<= 1;
                    if (g(op(sm, d[l]))) sm = op(sm, d[l++]);
                }
                return l - num;
            }
            // OKだったら一つ右にずれる、配列の端にいたらl=2^xの形になる
            sm = op(sm, d[l++]);
        } while ((l & -l) != l);
        return basesize;
    }
    template <bool (*g)(S)> int min_left(int r) {
        assert(0 <= r && r <= basesize);
        assert(g(e));
        if (r == 0) return 0;
        r += num;
        for (int i = depth; i >= 1; i--) push((r - 1) >> i);
        S sm = e;
        do {
            r--;
            while ((r & 1) && r > 1) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < num) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) sm = op(d[r--], sm);
                }
                return r + 1 - num;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }
};

struct S {
    mint val, ten;
};
using F = int;

S op(S l, S r) { return S{l.val + r.val, l.ten + r.ten}; }
S e = S{0, 0};
S mapping(F l, S r) {
    if (!l) return r;
    return S{r.ten * l, r.ten};
}
F composition(F l, F r) {
    if (!l) return r;
    return l;
}
F id = 0;

int main() {
    PRE_COMMAND
    int n, q, l, r, d;
    mint now{1};
    cin >> n >> q;
    vector<S> a(n);
    for (int i = n - 1; i >= 0; i--) {
        a[i] = S{now, now};
        now *= 10;
    }
    lazy_segtree<S, op, F, mapping, composition> seg(a, e, id);
    for (int i = 0; i < q; i++) {
        cin >> l >> r >> d;
        seg.apply(l - 1, r, d);
        cout << seg.all_prod().val << endl;
    }
}


Measured memory_bytes: 15552