#include<bits/stdc++.h>
#define int long long
#define double long double
#define INF INT_MAX
using namespace std;
const int maxn=5e4+5;
int n,m;
char a[maxn];
struct node {
int l,r;
mutable int v;
node(int L,int R=0,int V=0) : l(L),r(R),v(V) {}
bool operator < (const node &x) const {
return l<x.l;
}
};
set<node> ODT;
set<node>::iterator spilit(int pos) {
set<node>::iterator it=ODT.lower_bound(node(pos));
if(it!=ODT.end() && it->l==pos) return it;
it--;
if(it->r<pos) return ODT.end();
int V=it->v,L=it->l,R=it->r;
ODT.erase(it);
ODT.insert(node(L,pos-1,V));
return ODT.insert(node(pos,R,V)).first;
}
void bulldoze(int l,int r,int x) {
set<node>::iterator itr=spilit(r+1),itl=spilit(l);
ODT.erase(itl,itr);
ODT.insert(node(l,r,x));
}
int countt(int l,int r,int d){
set<node>::iterator itr=spilit(r+1),itl=spilit(l);
int ans=0;
for(;itl!=itr;itl++){
if(itl->v==d) ans+=(itl->r-itl->l+1);
}
return ans;
}
struct nodee{int l,r,d;}K[maxn];
bool cmp(nodee h,nodee g){return h.d<g.d;}
void Sort(int l,int r){
set<node>::iterator itr=spilit(r+1),itl=spilit(l);
int cnt=0,top=l;
for(;itl!=itr;itl++){
K[++cnt].l=itl->l;
K[cnt].r=itl->r;
K[cnt].d=itl->v;
}
ODT.erase(itl,itr);
sort(K+1,K+1+cnt,cmp);
for(int i=1;i<=cnt;i++){
ODT.insert(node(top,top+(K[i].r-K[i].l+1),K[i].d));
top+=(K[i].r-K[i].l+1);
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
ODT.insert(node(i,i,a[i]-'A'));
}
while(m--){
int op,x,y;
char k;
cin>>op>>x>>y;
if(op==1){
cin>>k;
int p=k-'A';
cout<<countt(x,y,p)<<endl;
}
else if(op==2){
cin>>k;
int p=k-'A';
bulldoze(x,y,p);
}
else Sort(x,y);
}
return 0;
}