#include <iostream>
#include <map>
#include <list>
#include <set>
#include <algorithm>
#include <vector>
#include <sstream>
#include <string>
#include <functional>
#include <queue>
#include <deque>
#include <stack>
#include <limits>
#include <unordered_map>
#include <unordered_set>
#include <cmath>
#include <fstream>
#include <iterator>
#include <random>
#include <chrono>


#define forr(i,start,count) for (int i = (start); i < (start)+(count); ++i)
#define set_map_includes(set, elt) (set.find((elt)) != set.end())
#define readint(i) int i; cin >> i
#define readll(i) ll i; cin >> i
#define readdouble(i) double i; cin >> i
#define readstring(s) string s; cin >> s

typedef long long ll;

using namespace std;

//ll modd = 1000 * 1000 * 1000 + 7;
ll modd = 998244353;

template<class T, class S>
class LazySegmentTree {
    // Lazy propagation segment tree, containing elts of type T; S is type ("paramter space type") for all possible function we'll be
    // applying to elts (thee funcs should commute with f; f should be associative)
    public:
      typedef function<T(T)> application_type;
     
      // f is combining function, should be associative; zero_value is identity for f as a grupoid operation;
      // com is composition of application functions, specifically com(a1, a2) is a1 \circ a2 ie com(a1,a2)(t)=a1(a2(t))
      // param is parametrization of application functions
      // id_ is parameter for identity application function
      // typical example if you have min segtree, and you want to assign values in a lazy way to interval:
      // T=int,S=int, f(x,y) = min(x,y), zero_value = +infty"=modd"; com(a,b)=a; 
      // param(a) = [](int a){ return function<int(int)>([](int x){return a;}); }
      // id_ = say modd+1; and param(modd+1) should be identity, and comm should accomodate that
      
      LazySegmentTree(const vector<T>& data, function<T(T,T)> f_, T zero_value,
        function<S(S,S)> com, function<application_type(S)> param, S id_) : zv(zero_value), f(f_), composition(com),
            paramtrization(param), ident(id_) {   
          Initialize(data);
      }

      T operator[](int i) {
          return GetEvaluation(i, i+1);
      }

      T GetEvaluation(int L, int R) {   // "min/max" on interval [L,R); 0-based indexing, as usual
        if (R<=L) {  return zv;  }
        return GetEvaluationHelper(L, R, 0, B, 1, ident);
      }

      void SetVal(int L, int R, S g) {  // set on interval [L,R); 0-based indexing
          if (R<=L) {  return;  }
          SetValHelper(L, R, 0, B, 1, g);
      }

      private:
        vector<T> tree;
        vector<S> application_function_below;
        int B;  // power of two greater than size of input data
        T zv;
        function<T(T,T)> f;
        function<S(S,S)> composition;
        function<application_type(S)> paramtrization;
        S ident;

        void Initialize(const vector<T>& data) {
    	  B = 1;
          while(B < data.size()) {B *= 2;  }
          tree = vector<T>(2*B, zv);
          copy(data.begin(), data.end(), next(tree.begin(), B));
          for(int i = B - 1; i >= 1; --i) {
  	  	     tree[i] = f(tree[2*i], tree[2*i+1]);
          }
          application_function_below = vector<S>(2*B, ident);
        }

      T GetEvaluationHelper(int L, int R, int start, int length, int tree_index, S accumulate) {
          if (L==R) {  return zv; }
          if ((L==start) && (R==start+length)) {   return paramtrization(accumulate)(tree[tree_index]);  }
          int midpoint = start + length/2;
          T left_ = zv, right_ = zv;

          if (L<=min(midpoint,R)) {
            left_ = GetEvaluationHelper(L, min(midpoint,R), start, length/2, 2*tree_index, composition(accumulate, application_function_below[tree_index]));
          }
          if (max(midpoint,L)<=R) {
            right_ = GetEvaluationHelper(max(midpoint,L), R, midpoint, length/2, 2*tree_index+1, composition(accumulate, application_function_below[tree_index]));
          }
          return f(left_, right_);
      }

      void SetValHelper(int L, int R, int start, int length, int tree_index, S g) {
          if (L==R) {  return; }
          if ((L==start) && (R==start+length)) {
              tree[tree_index] = paramtrization(g)(tree[tree_index]);
              application_function_below[tree_index] = composition(g, application_function_below[tree_index]);
              return;  }
          int midpoint = start + length/2;
          application_function_below[2*tree_index] = composition(application_function_below[tree_index], application_function_below[2*tree_index]);
          application_function_below[2*tree_index+1] = composition(application_function_below[tree_index], application_function_below[2*tree_index+1]);
          tree[2*tree_index] = paramtrization(application_function_below[tree_index])(tree[2*tree_index]);
          tree[2*tree_index+1] = paramtrization(application_function_below[tree_index])(tree[2*tree_index+1]);
          application_function_below[tree_index] = ident;

          if (L<=min(midpoint,R)) {
            SetValHelper(L, min(midpoint,R), start, length/2, 2*tree_index, g);
          }
          if (max(midpoint,L)<=R) {
            SetValHelper(max(midpoint,L), R, midpoint, length/2, 2*tree_index+1, g);
          }
          tree[tree_index] = f(tree[2*tree_index], tree[2*tree_index+1]);
      }

};

template<class T>
T fastpower(T x, ll pw) {
    T w = x, res = 1;
    while (pw>0) {
        if (pw&1) {
            res *= w; res %= modd;
        }
        pw >>= 1;
        w *= w; w %= modd;
    }
    return res;
}


int main()   {

      ios_base::sync_with_stdio(false);

      cout.precision(17);
      mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
      uniform_int_distribution<int> rand_gen(0, modd);   // rand_gen(rng) gets the rand no

//    readint(test_cases);
    int test_cases = 1;
    forr(t, 1, test_cases) {
        readint(n); readint(q);
        vector<pair<ll,ll>> data(n, make_pair(1, 10));
        LazySegmentTree<pair<ll,ll>, pair<ll,ll>> seg(data, [](pair<ll,ll> x, pair<ll,ll> y){ 
            return make_pair((x.first*y.second+y.first) % modd, (x.second*y.second) % modd);
        }, make_pair(0, 1), [](pair<ll,ll> y, pair<ll,ll> x){  return make_pair((x.first*y.first) % modd, 
             (y.first*x.second+y.second) % modd); }, [](pair<ll,ll> x){
            return [x](pair<ll,ll> xx) { return make_pair((xx.first*x.first+x.second*(modd+1-xx.second))%modd, xx.second);};
        } , make_pair(1,0));

        ll invv = fastpower<ll>(modd-9, modd-2);
        forr(i,0,q) {
          readint(a); readint(b); readint(d);

          seg.SetVal(a-1, b, make_pair(0, (invv*d) % modd));
          cout << seg.GetEvaluation(0, n).first << endl;
        }

    }
    return 0;
}


Measured memory_bytes: 22780