#include <bits/stdc++.h>

using namespace std;

typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<vvi> vvvi;
typedef long long ll;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<int,int> pi;
typedef pair<ll,ll> pll;
typedef vector<pi> vpi;
typedef vector<bool> vbool;

#define pb push_back
#define eb emplace_back
#define mp make_pair
#define forall(it,s) for(auto it = s.begin(); it != s.end(); ++it)
#define F0(var,n) for(ll var = 0; var < n; var++)
#define F1(var,n) for(ll var = 1; var <= n; var++)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define per(i,a,b) for(int i = b-1; i >= a; i--)
#define FIN ios::sync_with_stdio(false);cin.tie(0);
#define db(x) cout<<#x<<" = "<<x<<"\n"
#define all(v) v.begin(),v.end()
#define modulo(a,b) ((a%b)+b)%b
#define F first
#define S second
#define INF 1000000010
#define INFLL 1000000000000000000
#define eps 0.000000000001
#define mod 998244353
template<class C> void mini(C&a, C b){ a=min(a, b);}
template<class C> void maxi(C&a, C b){a=max(a,b);}
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}

//=======================//

vll pot10;
vll sum_pot10;

/*
Cosas que hay que cambiar cada vez que se quiere usar el segment tree (lo demas es general, sirve siempre):
NO_OPERATION
struct item
single()
merge()
*/

/*struct item {
	ll sum;   //sum of the whole segment
	ll seg;   // maximum sum of a subsegment in the segment
	ll pref;  // maximum sum of a prefix of the segment
	ll suf;   // maximum sum of a suffix of the segment
};*/
typedef long long item;

/*
Tengo dos operaciones asociativas: + y *, que ademas cumplen distributividad: (a+b)*c = a*c + b*c.
El segment tree soporta pedir + sobre un segmento y aplicar (*x) a todos los elementos de un segmento.
Cosas que hay que cambiar cada vez que se quiere usar el segment tree (lo demas es general, sirve siempre):
---------------
NEUTRAL_ELEMENT : Elemento neutro de +
---------------
struct item : El tipo de los nodos del arbol.
---------------
single() : Dado un elemento, convertirlo a un nodo que representa el segmento con ese solo elemento.
---------------
value_to_operation() : Dado un valor, convertirlo al valor que representa aplicar una operacion con ese
valor. Por lo general es la función identidad.
---------------
operation() : La operacion * (Dado un item y una operacion_t, la aplica sobre el item)
---------------
merge() : La operacion +
---------------
operation_t : El tipo de las operaciones, en general es simplemente un numero.
---------------
join_operations() : La operacion * entre elementos de tipo operacion (La operacion de la izquierda es la mas anterior)
*/

typedef long long operation_t;
typedef long long item;

struct lazy_segtree {
	int size;
	int cant_elems;
	vector<item> values;
	vector<operation_t> operations;
	operation_t NO_OPERATION = LLONG_MAX;
	item NEUTRAL_ELEMENT = 0; //Elemento neutro de query

	item single(long long v, int pos) {
		item res = v * pot10[cant_elems - pos - 1];
		res %= mod;
		return res;
	}

	operation_t value_to_operation(long long v) {
		return v;
	}

	void init(int n) {
		size = 1;
		cant_elems = n;
		while(size < n) size *= 2;
		values.assign(size*2, single(0LL, 0));
		operations.assign(size*2, NO_OPERATION);
	}

	item merge(item a, item b) { //Mergear dos resultados de query
		item res = a+b;
		res %= mod;
		return res;
	}

	operation_t join_operations(operation_t a, operation_t b) { //Operacion que hacemos sobre un segmento
		if (b == NO_OPERATION) return a;
		return b;
	}

	void apply_join_operations(operation_t& a, operation_t b) {
		a = join_operations(a,b);
	}

	item operation(item a, operation_t b, int lx, int rx) {
		if (b == NO_OPERATION) return a;
		int min_pot = cant_elems - rx;
		int max_pot = cant_elems - lx - 1;
		ll r = min_pot == 0 ? 0 : sum_pot10[min_pot - 1];
		item res = modulo(sum_pot10[max_pot] - r, mod);
		res *= b;
		res %= mod;
		return res;
	}

	void apply_operation_to_value(item& a, operation_t b, int lx, int rx) {
		a = operation(a,b,lx,rx);
	}

	void propagate(int x, int lx, int rx) {
		if (rx - lx == 1 || operations[x] == NO_OPERATION) return;
		int m = (lx + rx) / 2;
		apply_join_operations(operations[2*x+1], operations[x]);
		apply_operation_to_value(values[2*x+1], operations[x], lx, m);
		apply_join_operations(operations[2*x+2], operations[x]);
		apply_operation_to_value(values[2*x+2], operations[x], m, rx);
		operations[x] = NO_OPERATION;
	}

	void build(int node, int lx, int rx, vector<long long>& a) {
		if (rx-lx == 1) {
			if (lx < (int) a.size()) {
				values[node] = single(a[lx], lx);
			}
			return;
		}
		int m = (lx + rx) / 2;
		build(2*node+1, lx, m, a);
		build(2*node+2, m, rx, a);
		values[node] = merge(values[2*node+1], values[2*node+2]);
	}

	void build(vector<long long>& a) {
		build(0,0,size,a);
	}

	void apply(int L, int R, operation_t a, int node, int lx, int rx) {
		propagate(node, lx, rx);
		if (L >= rx || R <= lx) return;
		if (lx >= L && rx <= R) {
			apply_join_operations(operations[node], a);
			apply_operation_to_value(values[node], a, lx, rx);
			return;
		}
		int m = (lx+rx) / 2;
		apply(L,R,a,2*node+1,lx,m);
		apply(L,R,a,2*node+2,m,rx);
		values[node] = merge(values[2*node+1], values[2*node+2]);
	}

	void apply(int l, int r, long long a) {
		operation_t op = value_to_operation(a);
		apply(l,r,op,0,0,size);
	}

	item get(int node, int lx, int rx, int L, int R) {
		propagate(node, lx, rx);
		if (L >= rx || R <= lx) return 0;
		if (lx >= L && rx <= R) {
			return values[node];
		}
		int m = (lx+rx) / 2;
		long long r1 = get(2*node+1,lx,m,L,R);
		long long r2 = get(2*node+2,m,rx,L,R);
		return merge(r1, r2);
	}

	item get(int L, int R) {
		return get(0,0,size,L,R);
	}

	void debug() {
		cout << "\n";
		for(int x = 0; x < size; x++) {
			cout << "arr[" << x << "] = " << get(x, x+1) << "\n";
		}
	}

/*
	void debug_tree() {
		cout << "\n";
		for(int i = 0; i < size*2; i++) {
			cout << "nodo[" << i << "] = " << values[i] << "\n";
			cout << "operacion[" << i << "] = " << operations[i].first  << " " << operations[i].second << "\n";

		}
	}*/

};




int main () {
	FIN
	int n,q; cin >> n >> q;
	sum_pot10 = pot10 = vll(n+2);
	pot10[0] = 1;
	sum_pot10[0] = 1;
	for (int i = 1; i < n+2; i++) {
		pot10[i] = 10 * pot10[i-1];
		pot10[i] %= mod;
		sum_pot10[i] = sum_pot10[i-1] + pot10[i];
		sum_pot10[i] %= mod;
	}
	lazy_segtree st;
	st.init(n);
	vll unos(n,1);
	st.build(unos);
	while(q--) {
		//st.debug();
		int l,r; cin >> l >> r; l--;
		int d; cin >> d;
		st.apply(l,r,d);
		cout << st.get(0,n) << "\n";
	}

	return 0;
}










Measured memory_bytes: 16128