#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define lli long long int
#define pii pair<int,int>
#define vii vector<pii>
#define pb push_back
#define eb emplace_back
#define em emplace
#define all(v)  v.begin(),v.end()
#define mod 1000000007
#define vi vector<int>
#define vl vector<lli>
#define vll vector<pair<lli,lli>>
#define pll pair<lli,lli>
#define vvi vector<vector<int>>
#define vvl vector<vector<lli>>
#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
#define tk(args...) take(args);
#define posLSB(X) __builtin_ctz(X)
#define num1bit(X) __builtin_popcount(X)
#define numlead0(X) __builtin_clz(X)
#define umreserve(X) X.reserve(32768); X.max_load_factor(0.25);
void err(istream_iterator<string> it) {} template<typename T, typename... Args> void err(istream_iterator<string> it, T a, Args... args) { cout << *it << " = " << a << "\n"; err(++it, args...);}
void take() {} template<typename T, typename... Args> void take( T & a, Args & ... args ) { cin>>a; take(args...); }
template<class T>
void printvec(vector<T> &a){
	for(T &x:a){
		cout<<x<<" ";
	}
	cout<<endl;
}
template<class T>
void printarr(T a[],lli n){
	for(lli i=0;i<n;i++){
		cout<<a[i]<<" ";
	}
	cout<<endl;
}
struct HASH{
  size_t operator()(const pair<int,int>&x)const{
    return (size_t) x.first * 37U + (size_t) x.second;
  }
};

#define endl "\n"

lli add(lli a, lli b) {
	a += b;
	if (a >= mod) a -= mod;
	return a;
}

lli mul(lli a, lli b) {
	return a * 1ll * b % mod;
}

inline bool setmin(lli &x, lli y) { return (y < x) ? x = y, 1 : 0; }
inline bool setmax(lli &x, lli y) { return (y > x) ? x = y, 1 : 0; }

lli power_mod(lli a,lli x){if(x==0) return 1;lli y=power_mod(a,x/2);lli ans=(y*y)%mod; if(x%2) ans=(ans*a)%mod;return ans;}
lli inv(lli a){return power_mod(a,mod-2);}
lli power(lli a, lli x){ if(x==0) return 1; lli y= power(a,x/2); lli ans=(y*y); if(x%2) ans*=a; return ans;}
int n;
struct data
{
	lli sum, pref, suff, ans;
};
vector<int> t;
int combine(int l, int r)
{
	return l|r;
}
int make_data(int val)
{
	return val;
}

void build(vector<int> &a, int v, int tl, int tr)
{
	if (tl == tr)
	{
		t[v] = make_data(a[tl]);
	}
	else
	{
		int tm = (tl + tr) / 2;
		build(a, v * 2, tl, tm);
		build(a, v * 2 + 1, tm + 1, tr);
		t[v] = combine(t[v * 2], t[v * 2 + 1]);
	}
}

void update(int v, int tl, int tr, int pos, int new_val)
{
	if (tl == tr)
	{
		t[v] = make_data(new_val);
	}
	else
	{
		int tm = (tl + tr) / 2;
		if (pos <= tm)
			update(v * 2, tl, tm, pos, new_val);
		else
			update(v * 2 + 1, tm + 1, tr, pos, new_val);
		t[v] = combine(t[v * 2], t[v * 2 + 1]);
	}
}
int query(int v, int tl, int tr, int l, int r)
{
	if (l > r)
		return make_data(0);
	if (l == tl && r == tr)
		return t[v];
	int tm = (tl + tr) / 2;
	if (r <= tm)
	{
		return query(2 * v, tl, tm, l, r);
	}
	if (l > tm)
	{
		return query(2 * v + 1, tm + 1, tr, l, r);
	}

	return combine(query(v * 2, tl, tm, l, tm),
				   query(v * 2 + 1, tm + 1, tr, tm + 1, r));
}

// n IS NOW A GLOBAL VARIABLE...DONT MODIFY IT ,,, JUST STOP!!!
// PLEASE TYPE t.assign(4*n,0) or something similar in the MAIN FUNCTION...THANK YOU!!!
// for root v=1,tl=0,tr=n-1

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n;
	t.assign(4*n,(0));

	string s;
	cin>>s;
	for(int i=0;i<n;i++){
		update(1,0,n-1,i,((1<<(s[i]-'a'))));
	}
	int q;
	cin>>q;
	for(int loop=0;loop<q;loop++){
		int type;
		cin>>type;
		if(type==1){
			int ind;
			char ch;
			cin>>ind>>ch;
			ind--;
			update(1,0,n-1,ind,(1<<(ch-'a')));
		}
		else{
			int l,r;
			cin>>l>>r;
			l--;r--;
			int ret=query(1,0,n-1,l,r);
			cout<<__builtin_popcount(ret)<<endl;
		}
	}
}

Measured memory_bytes: 8980