#include<bits/stdc++.h>
using namespace std;
const int mod=998244353,N=2e5+100;
typedef long long ll;
int n,q,f[10][N],a[N],p10[N*9+1];
struct TreeNode{
int val,pow,tag;
}tr[N<<2];
inline int get(int x){
int res=0;
while(x) ++res,x/=10;
return res;
}
inline TreeNode pushup(TreeNode ls, TreeNode rs){
TreeNode rt;
rt={((ll)ls.val*p10[rs.pow]+rs.val)%mod,ls.pow+rs.pow,0};
return rt;
}
inline void pushdown(int k,int l,int r,int mid) {
int tag=tr[k].tag;
if(tag){
int q=get(tag);
tr[k<<1]={(ll)f[q][mid-l+1]*tag%mod,(mid-l+1)*q,tag};
tr[k<<1|1]={(ll)f[q][r-mid]*tag%mod,(r-mid)*q,tag};
tag=0;
}
}
void build(int l,int r,int k){
if(l==r){
tr[k]={a[l-1],get(a[l-1]),0};
return;
}
int mid=l+r>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
tr[k]=pushup(tr[k<<1],tr[k<<1|1]);
}
TreeNode query(int l,int r,int k,int x,int y){
// cout<<l<<' '<<r<<' '<<tr[k].val<<endl;
if(x<=l&&r<=y)
return tr[k];
int mid=l+r>>1;
pushdown(k,l,r,mid);
if(y<=mid) return query(l,mid,k<<1,x,y);
else if(x>mid) return query(mid+1,r,k<<1|1,x,y);
return pushup(query(l,mid,k<<1,x,y),query(mid+1,r,k<<1|1,x,y));
}
void update(int l,int r,int k,int x,int y,int v){
if(x<=l&&r<=y){,,.
int q=get(v);
// cout<<l<<' '<<r<<' '<<awa<<endl;
tr[k]={(ll)f[q][r-l+1]*v%mod,(r-l+1)*q,v};
return;
}
int mid=l+r>>1;
pushdown(k,l,r,mid);
if(x<=mid) update(l,mid,k<<1,x,y,v);
if(y>mid) update(mid+1,r,k<<1|1,x,y,v);
tr[k]=pushup(tr[k<<1],tr[k<<1|1]);
}
signed main(){
scanf("%d%d",&n,&q); ll p=1;
for(int i=1;i<=9;i++){
p*=10; p10[i]=(p%=mod);
for(int j=1;j<=n;j++)
f[i][j]=((ll)f[i][j-1]*p+1)%mod;
}
for(int i=10;i<=n*9;i++) p10[i]=(ll)p10[i-1]*10%mod;
for(int i=0;i<n;i++) scanf("%d",a+i);
build(1,n,1);
for(int i=0;i<q;i++){
int op,l,r,v;
scanf("%d%d%d",&op,&l,&r);
if(op==1){
scanf("%d",&v);
update(1,n,1,l,r,v);
}else printf("%d\n",query(1,n,1,l,r).val);
}
return 0;
}
/*
10 10
1 2 3 4 5 6 7 8 9 10
1 1 3 3
2 2 4
*/
WA了一个点,求调QWQ