#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
#include <queue>
#include <fstream>
#include <string>
#include <math.h>
#include <set>
#include <string>
#include <bitset>
#include <fstream>
#include <stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;
typedef pair<ll, P> T;

#define rep(i, n) for (ll i = 0; i < (n); i++)
#define revrep(i, n) for (ll i = (n) - 1; i >= 0; i--)
#define f first
#define s second
#define pb push_back

ll mod = 1000000007;
const ll INF = 100000000000010000;
//const ull B = 998244353;
//ll kai[3010];

//void pres(double A, ll x = 20) { printf("%.20f\n", x); }

vector<ll> dx = { 0, 1, 0, -1, 1, -1, 1, -1, 0};
vector<ll> dy = { 1, 0, -1, 0, 1, 1, -1, -1, 0};

void chmin(ll& x, ll y) {
	x = min(x, y);
}

void chmax(ll& x, ll y) {
	x = max(x, y);
}

ll pow_long(ll x, ll y) {
	ll res = 1;
	while (y > 0) {
		if (y % 2 == 1) res *= x;
		x *= x;
		y /= 2;
	}
	return res;
}

void test() {
	cout << "888888888888888888888888" << endl;
}

ll gcd(ll x, ll y) {
	if (y == 0) return x;
	return gcd(y, x % y);
}

ll pow_mod(ll x, ll k) {
	x %= mod;
	ll res = 1;
	while (k > 0) {
		if (k % 2) {
			res *= x; res %= mod;
		}
		x *= x; x %= mod;
		k /= 2;
	}
	return res;
}

ll div_mod(ll x) {
	return pow_mod(x, mod - 2);
}

//コンビネーション
const int MAXcomb = 1000010;
ll fac[MAXcomb], finv[MAXcomb], inv[MAXcomb];
//facはn!,finvは1/n!
//invは逆元
void COMinit() {
	fac[0] = fac[1] = 1;
	finv[0] = finv[1] = 1;
	inv[1] = 1;
	for (int i = 2; i < MAXcomb; i++) {
		fac[i] = fac[i - 1] * i % mod;
		inv[i] = mod - inv[mod%i] * (mod / i) % mod;
		finv[i] = finv[i - 1] * inv[i] % mod;
	}
}
ll comb(int n, int k) {
	if (n < k) return 0;
	if (n < 0 || k < 0) return 0;
	return fac[n] * finv[k] % mod * finv[n - k] % mod;
}

vector <ll> par; // 各元の親を表す配列
vector <ll> siz; // 素集合のサイズを表す配列(1 で初期化)

void init_u(ll sz_) {
	par.resize(sz_);
	siz.assign(sz_, 1LL);  // resize だとなぜか初期化されなかった
	for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
}

// Member Function
// Find
ll root(ll x) { // 根の検索
	while (par[x] != x) {
		x = par[x] = par[par[x]]; // x の親の親を x の親とする
	}
	return x;
}

// Union(Unite, Merge)
bool merge(ll x, ll y) {
	x = root(x);
	y = root(y);
	if (x == y) return false;
	// merge technique（データ構造をマージするテク．小を大にくっつける）
	if (siz[x] < siz[y]) swap(x, y);
	siz[x] += siz[y];
	par[y] = x;
	return true;
}

bool issame(ll x, ll y) { // 連結判定
	return root(x) == root(y);
}

ll size(ll x) { // 素集合のサイズ
	return siz[root(x)];
}

ll bit[500010][30];

ll sum(ll i, ll r)
{
	i += 1;
	ll t = 0;
	while (i > 0)
	{
		t += bit[i][r];
		i -= i & -i;
	}
	return t;
}

void add(ll i, ll x, ll r)
{
	i += 1;
	while (i <= 500005)
	{
		bit[i][r] += x;
		i += i & -i;
	}
}

ll N;
string S;
ll Q;

void solve() {
	cin >> N;
	cin >> S;
	cin >> Q;
	rep(i, N) {
		add(i + 1, 1, (S[i] - 'a'));
	}
	rep(i, Q) {
		ll q;
		cin >> q;
		if (q == 1) {
			ll I;
			char C;
			cin >> I >> C;
			rep(j, 26) {
				if (sum(I, j) - sum(I - 1, j) > 0) add(I, -1, j);
			}
			add(I, 1, (C - 'a'));
		}
		else {
			ll l, r, su = 0;
			cin >> l >> r;
			rep(j, 26) {
				if (sum(r, j) - sum(l - 1, j) > 0) su++;
			}
			cout << su << endl;
		}
	}
	
}

int main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	ll T = 1;
	//cin >> T;
	rep(i, T) solve();
}


Measured memory_bytes: 119708