#pragma GCC optimize("Ofast")
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,n) for(int i=0;i<n;i++)
#define rep2(i,s,f) for(int i=s;i<f;i++)
#define INF 1000000000000000000
#define MOD 1000000007
typedef pair<int, int> P;

bool prime(int n) {
	for (int i = 2; i <= sqrt(n); i++) {
		if (n % i == 0)return false;
	}
	return n != 1;
}
int gcd(int x, int y) {
	if (y == 0)return x;
	return gcd(y, x % y);
}
int lcm(int x, int y) {
	return x / gcd(x, y) * y;
}
int mod_pow(int n, int p, int m) {
	if (p == 0) return 1;
	if (p % 2 == 0) {
		int t = mod_pow(n, p / 2, m);
		return (t * t) % m;
	}
	return n * mod_pow(n, p - 1, m) % m;
}
int extGCD(int a, int b, int& x, int& y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	long long d = extGCD(b, a % b, y, x);
	y -= a / b * x;
	return d;
}
int modinv(int a, int m) {
	int b = m, u = 1, v = 0;
	while (b) {
		long long t = a / b;
		a -= t * b; swap(a, b);
		u -= t * v; swap(u, v);
	}
	u %= m;
	if (u < 0) u += m;
	return u;
}
int digit(int x) {
	int cnt = 0;
	while (x > 0) {
		cnt += x % 10;
		x /= 10;
	}
	return cnt;
}
int read() {
	int tmp;
	cin >> tmp;
	return tmp;
}
int xor128() {
	static int x = 123456789, y = 362436069, z = 521288629, w = 88675123;
	int t = (x xor (x << 11));
	x = y; y = z; z = w;
	return (w = (w xor (w >> 19)) xor (t xor (t >> 8)));
}
map<int, int> factaring(int x) {
	map<int, int>ans;
	int now = 2;
	while (now * now <= x) {
		if (x % now == 0) {
			x /= now;
			ans[now]++;
		}
		else now++;
	}
	if (x != 1) ans[x]++;
	return ans;
}

const int MAX = 510000;

long long fac[MAX], finv[MAX], inv[MAX];

// テーブルを作る前処理
void COMinit() {
	fac[0] = fac[1] = 1;
	finv[0] = finv[1] = 1;
	inv[1] = 1;
	for (int i = 2; i < MAX; 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;
	}
}

// 二項係数計算
long long COM(int n, int k) {
	if (n < k) return 0;
	if (n < 0 || k < 0) return 0;
	return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

int MY_COM(int n, int k) {
	int x = 1, y = 1;
	rep(i, k) {
		y *= i + 1;
		y %= MOD;
	}
	for (int i = n - k + 1; i <= n; i++) {
		x *= i;
		x %= MOD;
	}
	return x * modinv(y, MOD) % MOD;
}

class UnionFind {
private:
	vector<int>par;
public:
	//宣言
	UnionFind(int n) {
		for (int i = 0; i < n; i++) par.push_back(-1);
	}

	//根を求める
	int root(int x) {
		if (par[x] < 0) return x;
		else return par[x] = root(par[x]);
	}

	//同じグループか
	bool same(int x, int y) {
		return root(x) == root(y);
	}

	//併合
	void unite(int x, int y) {
		x = root(x), y = root(y);
		if (x == y) return;
		if (par[x] > par[y]) swap(x, y);
		par[x] += par[y];
		par[y] = x;
		return;
	}

	//連結成分のサイズ
	int size(int x) {
		return -par[root(x)];
	}
};

class BIT {
private:
	vector<int>bit;
	int n;
public:
	BIT(int _n) {
		bit.resize(_n + 1);
		rep(i, _n + 1) bit[i] = 0;
		n = _n;
	}

	BIT() {
		n = 0;
	}

	void set(int _n) {
		bit.resize(_n + 1);
		rep(i, _n + 1) bit[i] = 0;
		n = _n;
	}

	int get() {
		return bit.size();
	}

	int sum(int i) {
		int s = 0;
		while (i > 0) {
			s += bit[i];
			i -= (i & -i);
		}
		return s;
	}

	int sum(int i, int j) {
		int be = sum(i - 1);
		int af = sum(j);
		return af - be;
	}

	void add(int i, int x) {
		while (i <= n) {
			bit[i] += x;
			i += (i & -i);
		}
	}
};

int alp[500005];

signed main() {
	int n, q;
	string s;
	cin >> n;
	cin >> s;
	BIT bit[30];
	rep(i, 26) bit[i].set(n);
	rep(i, n) {
		bit[s[i] - 'a'].add(i + 1, 1);
		alp[i] = s[i] - 'a';
	}
	cin >> q;
	rep(i, q) {
		int qu;
		cin >> qu;
		if (qu == 1) {
			int a;
			char c;
			cin >> a >> c;
			bit[alp[a - 1]].add(a, -1);
			bit[c - 'a'].add(a, 1);
			alp[a - 1] = c - 'a';
		}
		else {
			int l, r;
			cin >> l >> r;
			int cnt = 0;
			rep(j, 26) {
				if (bit[j].sum(l, r) > 0) {
					cnt++;;
				}
			}
			cout << cnt << endl;
		}
	}

	return 0;
}


Measured memory_bytes: 106628