0 pts...
#include <bits/stdc++.h>
using namespace std;
inline void init() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
}
template<typename any>struct odt {
struct odt_node {
int l, r;
mutable any data;
odt_node(int _l, int _r = -1, any _data = 0):l(_l), r(_r), data(_data) {}
bool operator < (const odt_node &t) const {
return l < t.l;
}
};
std::set<odt_node> s;
auto insert(int l, int r = -1, any k = 0) {return s.emplace(l, r, k);}
inline auto split(int pos) {
auto it = s.lower_bound(pos);
if(it != s.end() and it->l == pos)return it;
--it;
int l = it->l, r = it->r;
any k = it->data;
s.erase(it);
insert(l, pos-1, k);
return insert(pos, r, k).first;
}
inline auto assign(int l,int r,any k) {
auto it_r = split(r + 1), it_l = split(l);
s.erase(it_l, it_r);
return insert(l, r, k).first;
}
inline auto Ruq(int l, int r, any k) {
int cnt = 0;
auto it_r = split(r + 1), it_l = split(l);
for(; it_l != it_r; ++it_l) {
if((it_l -> data) == k)
cnt++;
}
return cnt;
}
inline void Rsort(int l, int r) {
auto it_r = split(r + 1), it_l = split(l);
vector<pair<any, int> > Ins;
Ins.clear();
for(; it_l != it_r; ++it_l)
Ins.push_back({it_l -> data, it_l->l - it_r->r + 1});
sort(Ins.begin(), Ins.end());
}
};
odt<char> ODT;
int n, m;
int main() {
init();
cin >> n >> m;
for(int i = 1; i <= n; ++i)
ODT.insert(i, i, toupper(getchar()));
while(m--) {
int op, l, r;
cin >> op;
switch(op) {
case 1 : {
char k;
cin >> l >> r >> k;
cout << ODT.Ruq(l, r, toupper(k)) << "\n";
break;
}
case 2 : {
char k;
cin >> l >> r >> k;
ODT.assign(l, r, toupper(k));
break;
}
case 3 : {
cin >> l >> r;
ODT.Rsort(l, r);
break;
}
}
}
return 0;
}