#pragma GCC optimize("Ofast")
#pragma region head
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vi = vector<int>;
using vll = vector<ll>;
using pi = pair<int, int>;
using pll = pair<ll, ll>;
template <class T>
using vv = vector<vector<T>>;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define repi(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, n) for (int i = (int)(n)-1; i >= 0; i--)
#define rrepi(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define bit(n) (1LL << (n))
template <class T>
inline bool chmax(T& a, const T& b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T>
inline bool chmin(T& a, const T& b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
const int INF = 1002003004;
const ll LINF = 1002003004005006007ll;
struct preprocess {
    preprocess() {
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(20);
    }
} ____;
#pragma endregion head

#pragma region library
const int MOD = 998244353;
struct mint {
    ll x;  // typedef long long ll;
    mint(ll x = 0) : x((x % MOD + MOD) % MOD) {}
    mint operator-() const { return mint(-x); }
    mint& operator+=(const mint a) {
        if ((x += a.x) >= MOD) x -= MOD;
        return *this;
    }
    mint& operator-=(const mint a) {
        if ((x += MOD - a.x) >= MOD) x -= MOD;
        return *this;
    }
    mint& operator*=(const mint a) {
        (x *= a.x) %= MOD;
        return *this;
    }
    mint operator+(const mint a) const {
        mint res(*this);
        return res += a;
    }
    mint operator-(const mint a) const {
        mint res(*this);
        return res -= a;
    }
    mint operator*(const mint a) const {
        mint res(*this);
        return res *= a;
    }
    mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t >> 1);
        a *= a;
        if (t & 1) a *= *this;
        return a;
    }
    // for prime MOD
    mint inv() const {
        return pow(MOD - 2);
    }
    mint& operator/=(const mint a) {
        return (*this) *= a.inv();
    }
    mint operator/(const mint a) const {
        mint res(*this);
        return res /= a;
    }
    bool operator==(const mint a) const {
        return x == a.x;
    }
    bool operator!=(const mint a) const {
        return x != a.x;
    }
    friend ostream& operator<<(ostream& os, const mint& value) {
        os << value.x;
        return os;
    }
    friend istream& operator>>(istream& is, mint& value) {
        ll t;
        is >> t;
        value = mint(t);
        return is;
    }
};

// Time Complexity: build O(N), query O(logN)
template <typename T, typename U = T>
struct LazySegmentTree {
    // T should be Monoid (Associativity, Identity element)
    using FuncTT = function<T(T, T)>;
    using FuncTU = function<T(T, U)>;
    using FuncUU = function<U(U, U)>;
    int sz;          // size of array
    vector<T> data;  // 1-indexed(size: sz*2)
    vector<U> lazy;
    T identity;  // identity element
    U identityLz;
    FuncTT f;
    FuncTU g;
    FuncUU h;

    // node k: parent k/2, children (2*k, 2*k+1)
    LazySegmentTree(int n, const T& identity, const U& identityLz,
                    FuncTT f, FuncTU g, FuncUU h)
        : identity(identity), identityLz(identityLz), f(f), g(g), h(h) {
        sz = 1;
        while (sz < n) sz <<= 1;
        data.assign(2 * sz, identity);
        lazy.assign(2 * sz, identityLz);
    }
    void set(int idx, const T& val) {
        data[idx + sz] = val;
    }
    void build() {
        for (int idx = sz - 1; idx > 0; idx--) {
            data[idx] = f(data[2 * idx], data[2 * idx + 1]);
        }
    }
    inline void evaluate(int idx) {
        if (lazy[idx] != identityLz) {
            if (idx < sz) {
                lazy[2 * idx] = h(lazy[2 * idx], lazy[idx]);
                lazy[2 * idx + 1] = h(lazy[2 * idx + 1], lazy[idx]);
            }
                data[idx] = reflect(idx);
                lazy[idx] = identityLz;
        }
    }
    inline T reflect(int idx) {
        if (lazy[idx] != identityLz)
            return g(data[idx], lazy[idx]);
        else
            return data[idx];
    }
    void update(int a, int b, const U& x) { update(a, b, x, 1, 0, sz); }
    void update(int a, int b, const U& x, int idx, int l, int r) {
        evaluate(idx);
        if (b <= l || r <= a) return;
        if (a <= l && r <= b) {
            lazy[idx] = h(lazy[idx], x);
            evaluate(idx);
        } else {
            update(a, b, x, 2 * idx, l, (l + r) / 2);
            update(a, b, x, 2 * idx + 1, (l + r) / 2, r);
            data[idx] = f(data[2 * idx], data[2 * idx + 1]);
        }
    }
    // [a, b)
    // recursive implementation
    T query(int a, int b) { return query(a, b, 1, 0, sz); }
    T query(int a, int b, int idx, int l, int r) {
        if (r <= a || b <= l) return identity;
        evaluate(idx);
        if (a <= l && r <= b)
            return data[idx];
        else {
            T vl = query(a, b, idx * 2, l, (l + r) / 2);
            T vr = query(a, b, idx * 2 + 1, (l + r) / 2, r);
            return f(vl, vr);
        }
    }
    // ToDo: for-loop implementation
    // T query(int l, int r)
    T operator[](const int& idx) {
        return query(idx, idx + 1);
    }
};
// Time Complexity: build O(N), query O(logN)
template <typename T>
struct SegmentTree {
    // T should be Monoid (Associativity, Identity element)
    using Func = function<T(T, T)>;
    int sz;          // size of array
    vector<T> data;  // 1-indexed(size: sz*2)
    T identity;      // identity element
    Func f;          // binary operation
    // node k: parent k/2, children (2*k, 2*k+1)
    SegmentTree() = default;
    SegmentTree(int n, const T& identity, Func f) : identity(identity), f(f) {
        sz = 1;
        while (sz < n) sz <<= 1;
        data.assign(2 * sz, identity);
    }
    void set(int idx, const T& val) {
        data[idx + sz] = val;
    }
    void build() {
        for (int idx = sz - 1; idx > 0; idx--) {
            data[idx] = f(data[2 * idx], data[2 * idx + 1]);
        }
    }
    void update(int idx, const T& x) {
        idx += sz;
        data[idx] = x;
        while (idx >>= 1) {
            data[idx] = f(data[2 * idx], data[2 * idx + 1]);
        }
    }
    // [a, b)
    // recursive implementation
    T query(int a, int b) { return query(a, b, 1, 0, sz); }
    T query(int a, int b, int idx, int l, int r) {
        if (r <= a || b <= l) return identity;
        if (a <= l && r <= b)
            return data[idx];
        else {
            T vl = query(a, b, idx * 2, l, (l + r) / 2);
            T vr = query(a, b, idx * 2 + 1, (l + r) / 2, r);
            return f(vl, vr);
        }
    }
    // ToDo: for-loop implementation
    // T query(int l, int r)
    T operator[](const int& idx) const {
        return data[idx + sz];
    }
};
// Complexity: O(log n)
ll modpow(ll x, ll n, const ll mod) {
    if (!n) return 1;
    ll res = modpow(x * x % mod, n / 2, mod);
    if (n & 1) res = res * x % mod;
    return res;
}
#pragma endregion library
SegmentTree<mint> sg1;
using ti = tuple<mint, int, int>;
ti id = ti{0, -1, -1};
ti f(ti a, ti b) {
    if(a == id) return b;
    if(b == id) return a;
    mint a1, b1;
    int a2, a3, b2, b3;
    tie(a1, a2, a3) = a;
    tie(b1, b2, b3) = b;
    return ti{a1 + b1, min(a2, b2), max(a3, b3)};
}
ti g(ti a, int x) {
    if(a == id) return a;
    mint a1;
    int a2, a3;
    tie(a1, a2, a3) = a;
    mint val = 0;
    if (a2 != -1)
        val = sg1.query(a2, a3);
    return ti{val * x, a2, a3};
}
int h(int a, int b) {
    return b;
}
mint f2(mint a, mint b) {
    return a + b;
}

int main() {
    int n, q;
    cin >> n >> q;
    sg1 = SegmentTree<mint>(n, 0, f2);
    rep(i, n) {
        sg1.set(i, modpow(10, n - i - 1, MOD));
    }
    sg1.build();
    LazySegmentTree<ti, int> sg2(n, ti{0, -1, -1}, 0, f, g, h);
    rep(i, n) {
        mint val = sg1[i];
        sg2.set(i, ti{val, i, i + 1});
    }
    sg2.build();
    while (q--) {
        int l, r, d;
        cin >> l >> r >> d;
        l--;
        sg2.update(l, r, d);
        mint ans;
        tie(ans, ignore, ignore) = sg2.query(0, n);
        cout << ans << '\n';
    }
}


Measured memory_bytes: 17716