RT
#include <bits/stdc++.h>
using namespace std;
#define _r return *this
#define _o &operator
namespace IO { const int _S = 1 << 21; char b[_S], *p1 = b, *p2 = b, pb[_S], *pp = pb;
void fl() { fwrite(pb, 1, pp - pb, stdout), pp = pb; }
struct fr { char gc() { if (p1 == p2) p2 = (p1 = b) + fread(b, 1, _S, stdin); return p1 == p2 ? ' ' : *p1++; }
fr _o>>(char &c) { do c = gc(); while (c == ' ' || c == '\n' || c == '\r' || c == '\t'); _r; }
template <class T> fr _o>>(T &x) { char c = gc(); T f = 1; for (x = 0; !isdigit(c);) (c == '-' ? f = -1 : 1),
c = gc(); while (isdigit(c)) x = (x * 10) + (c ^ 48), c = gc(); x *= f; _r; } fr() {} } in;
struct fw { void pt(char c) { *pp++ = c; if (pp - pb == _S) fl(); } fw _o<<(char c) { pt(c); _r; }
template <class T> fw _o<<(T x) { if (!x) { pt(48); _r; } if(x < 0) pt('-'), x = -x;
int s[64], t = 0; while (x) s[++t] = x % 10, x /= 10; while (t) pt(s[t--] + 48); _r; }
fw _o<<(const char *s) { int c = 0; while (s[c]) pt(s[c++]); _r; } fw() {} } out;
struct fe { ~fe() { fl(); } } fls; } using IO::in; using IO::out;
#define _f(i, a, b) for (int i = a; i <= b; ++i)
#define _d(i, a, b) for (int i = a; i >= b; --i)
const int N = 5e4 + 5;
int n, m, tmp[30];
inline int num(char x)
{
if('a' <= x && x <= 'z')
return x - 'a' + 1;
return x - 'A' + 1;
}
struct segTree
{
int tr[N << 2], tag[N << 2];
inline int ls(int p) { return p << 1; }
inline int rs(int p) { return p << 1; }
void pushup(int p) { tr[p] = tr[ls(p)] + tr[rs(p)]; }
void update(int p, int l, int r, int k)
{
tr[p] = k ? (r - l + 1) : 0;
tag[p] = k;
}
void pushdown(int p, int l, int r)
{
if(tag[p] == -1)
return ;
int mid = l + r >> 1;
update(ls(p), l, mid, tag[p]);
update(rs(p), mid + 1, r, tag[p]);
tag[p] = -1;
}
void modify(int p, int x, int y, int l, int r, int k)
{
if(x <= l && r <= y)
{
update(p, l, r, k);
return ;
}
pushdown(p, l, r);
int mid = l + r >> 1;
if(x <= mid) modify(ls(p), x, y, l, mid, k);
if(y > mid) modify(rs(p), x, y, mid + 1, r, k);
pushup(p);
}
int query(int p, int x, int y, int l, int r)
{
if(x <= l && r <= y)
return tr[p];
int mid = l + r >> 1, ret = 0;
pushdown(p, l, r);
if(x <= mid) ret += query(ls(p), x, y, l, mid);
if(y > mid) ret += query(rs(p), x, y, mid + 1, r);
return ret;
}
} T[30];
signed main()
{
in >> n >> m;
_f(i, 1, 26) fill(T[i].tag, T[i].tag + (n << 2), -1);
_f(i, 1, n)
{
char ch; in >> ch;
T[num(ch)].modify(1, i, i, 1, n, 1);
}
while(m--)
{
int opt, x, y; char k;
in >> opt >> x >> y;
if(opt == 1)
{
in >> k;
out << T[num(k)].query(1, x, y, 1, n) << '\n';
continue;
}
int cnt = 0;
_f(i, 1, 26) tmp[i] = T[i].query(1, x, y, 1, n);
_f(i, 1, 26) if(tmp[i]) T[i].modify(1, x, y, 1, n, 0);
if(opt == 2) in >> k, T[num(k)].modify(1, x, y, 1, n, 1);
else _f(i, 1, 26) if(tmp[i]) T[i].modify(1, cnt + 1, cnt + tmp[i], 1, n, 1), cnt += tmp[i];
}
return 0;
}