#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ldb;
typedef pair<ll,ll> pll;
template <typename T> using ordered_set =  tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define V vector
#define endl "\n"
#define CLEAR(a) memset(a,0,sizeof(a))
#define all(x) x.begin(),x.end()
#define sz(x) ((ll)x.size())
#define rep0(i,n) for(ll i=0;i<n;i++)
#define rep1(i,n) for(ll i=1;i<=n;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ios_tie() ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); cerr.tie(nullptr)
#define trace1(a)             cout <<#a<<":"<<a<< endl;
#define trace2(a,b)           cout <<#a<<":"<<a<<" | "<<#b<<":"<<b<< endl;
#define trace3(a,b,c)         cout <<#a<<":"<<a<<" | "<<#b<<":"<<b<<" | "<<#c<<":"<<c<<endl;
#define trace4(a,b,c,d)       cout <<#a<<":"<<a<<" | "<<#b<<":"<<b<<" | "<<#c<<":"<<c<<" | "<<#d<<":"<<d<<endl;

const ll inf = 1e18;
const ll mod = 998244353;
const ll maxn = 2e5+1;
const ldb PI = acos(-1);

void lol(ll s) {cerr<<"check........................................... "<<s<<endl;}
ll power(ll x,ll y) {ll res=1; x%=mod; while(y) {if(y&1) res=(res*x)%mod; y>>=1LL; x=(x*x)%mod; }return res;}
ll inv(ll x) {return power(x,mod-2);}//(1/x)%y = x^(y-2) % y;   // pow(x,y)%m = pow(x,y%(m-1))%m
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

// If you copy paste my solution I will murder you in your sleep.
void init()
{

}

ll sumtree[4*maxn+1];
ll lazy[4*maxn+1];
ll upd[4*maxn+1];
ll A[maxn];

void fix(ll node, ll start, ll end)
{
    if(!upd[node]) {
        return;
    }
    sumtree[node] = (A[end]-A[start-1]+mod)*lazy[node]%mod;
    if(start!=end)
    {
        lazy[2*node] = lazy[node];
        lazy[2*node+1] = lazy[node];
        upd[2*node] = upd[2*node+1] = 1;
    }
    lazy[node] = 0;
    upd[node] = 0;
}

void buildsum(ll node, ll start, ll end)
{
    if(start == end)
        sumtree[node] = (A[end]-A[start-1]+mod)%mod;
    else
    {
        ll mid = (start + end) / 2;
        buildsum(2*node, start, mid);
        buildsum(2*node+1, mid+1, end);
        sumtree[node] = (sumtree[2*node] + sumtree[2*node+1])%mod;
    }
}

void updaterange(ll node, ll start, ll end, ll l, ll r, ll val)
{
    fix(node,start,end);
    if(start>end or start>r or end<l)
        return;
    if(start>=l and end<=r)
    {
        lazy[node] = val;
        upd[node] = 1;
        fix(node,start,end);
        return;
    }
    ll mid = (start + end) / 2;
    updaterange(2*node, start, mid, l, r, val);
    updaterange(2*node+1, mid+1, end, l, r, val);
    sumtree[node] = (sumtree[2*node] + sumtree[2*node+1])%mod;
}

ll queryrange(ll node, ll start, ll end, ll l, ll r)
{
    if(start > end or r < start or end < l)
        return 0;
    fix(node,start,end);
    if(l <= start and r >= end)
        return sumtree[node];
    ll mid = (start + end) / 2;
    ll p1 = queryrange(2*node, start, mid, l, r);
    ll p2 = queryrange(2*node+1, mid+1, end, l, r);
    return (p1 + p2)%mod;
}

void solve()
{
    ll n, q;
    cin>>n>>q;
    ll mul = 1;
    for(ll i=n;i>=1;i--) {
        A[i] = mul;
        mul = (mul*10)%mod;
    }
    rep1(i,n) {
        A[i] = (A[i] + A[i-1])%mod;
    }
    buildsum(1,1,n);
    while(q--) {
        ll l, r, d;
        cin>>l>>r>>d;
        updaterange(1,1,n,l,r,d);
        cout<<queryrange(1,1,n,1,n)<<endl;
    }
}

int main()
{
    ios_tie();
    // freopen("input.txt", "r", stdin);
    // freopen("myOut.txt", "w", stdout);
    ll _ = 1;
    // cin>>_;
    init();
    rep1(i,_)
    {
        // cout<<"Case #"<<i<<": ";
        solve();
    }
    return 0;
}


Measured memory_bytes: 17452