//#i#include "pch.h"
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <limits.h>
#include <string>
#include <stack>
#include <deque>
#include <cmath>
#include <bitset>
#include <complex>
#include <functional>
#include <time.h>
#include <cassert>
#include <stdio.h>

typedef long long ll;
typedef std::pair<int, int> Pii;
typedef std::pair<long long, long long> Pll;
typedef std::pair<double, double> Pdd;

#define rip(i, n, s) for (int i = (s);i < (int)( n ); i++)
#define mapa make_pair
#define all(a) a.begin(), a.end()
#define MM << " " <<

template<typename T>
using MaxHeap = std::priority_queue<T>;
template<typename T>
using MinHeap = std::priority_queue<T, std::vector<T>, std::greater<T>>;

template<typename T>
inline bool chmax(T &a, T b) {
	if (a < b) {
		a = b;
		return true;
	}
	return false;
}
template<typename T>
inline bool chmin(T &a, T b) {
	if (a > b) {
		a = b;
		return true;
	}
	return false;
}

template<typename T>
std::vector<T> vec(int len, T elem) { return std::vector<T>(len, elem); }
template<typename T>
void vdeb(std::vector<T> &da) {
	for (int i = 0;i < da.size();i++) {
		if (i == da.size() - 1) std::cout << da[i];
		else std::cout << da[i] << ' ';
	}
	std::cout << std::endl;
}
template<typename T>
void vdeb(std::vector<std::vector<T>> &da) {
	for (int i = 0;i < da.size();i++) vdeb(da[i]);
	std::cout << std::endl;
}

struct SegTree{ //0indexed
    std::vector<int> nod;
    int size;
    SegTree(int x){
        size=1;
        while(x>size){
            size*=2;
        }
        nod=std::vector<int>(size*2-1,0);
    }
    void update(int k,int a){
        k+=size-1;
        nod[k]|=a;//最下の処理
        while(k>0){
            k=(k-1)/2;
            nod[k]|=a; //下から上へ 
        }
    }
	void dedate(int k, int a){
		k += size-1;
		nod[k]-=a;
		while(k>0){
			k=(k-1)/2;
			nod[k] = nod[k*2+1]|nod[k*2+2];
		}
	}
    void Update(int a,int b,int k,int l,int r,int x){
        //[a,b)について
        //kは節点の番号,[l,r)はその節点がカバーする範囲
        if(r<=a||b<=l){ //[a,b)と[l,r)が重なって無いとき
            return;
        }
        if(a<=l && r<=b){ //[a,b)が[l,r)を完全に含んでいるとき
            nod[k] = std::max(x,nod[k]);
            return;
        }
        else{
            Update(a,b,k*2+1,l,(l+r)/2,x);
            Update(a,b,k*2+2,(l+r)/2,r,x);
            return;
        }
    }
    int query(int a,int b,int k,int l,int r){//a,b,0,0,st.size 
        //[a,b)について
        //kは節点の番号,[l,r)はその節点がカバーする範囲
        if(r<=a||b<=l){ //[a,b)と[l,r)が重なって無いとき
            return 0;
        }
        if(a<=l && r<=b){ //[a,b)が[l,r)を完全に含んでいるとき
            return nod[k];
        }
        else{
            return query(a,b,k*2+1,l,(l+r)/2)|query(a,b,k*2+2,(l+r)/2,r);
        }
    }
    void deb(){ //全ノードの出力
		for(int i=0;i<size*2-1;i++){
			if(i==size*2-2){
				std::cout << nod[i] <<std:: endl;
			}
			else{
				std::cout << nod[i] << ' ';
			}
		}
		return;
	}
};

int pop_c(int x){
	int ret = 0;
	while(x){
		ret += x&1;
		x /= 2;
	}
	return ret;
}

using namespace std;

int main(){
	int n,q;
	string s;
	cin >> n >> s >> q;
	SegTree st(n);
	auto adding = [&](int x, char c){
		st.dedate(x, 1<<(s[x]-'a'));
		st.update(x, 1<<(c-'a'));
		s[x] = c;
		return;
	};
	auto query = [&](int l, int r){
		int now =st.query(l, r+1, 0, 0, st.size);
		return pop_c(now);
	};
	rip(i,n,0) st.update(i, 1<<(s[i]-'a'));
	vector<int> ans(0);
	rip(i,q,0){
		int x;cin >> x;
		if(x == 1){
			int j;char c;
			cin >> j >> c;
			adding(j-1, c);
		}
		else{
			int l,r;cin >> l >> r;
			ans.push_back(query(l-1, r-1));
		}
	}
	rip(i,ans.size(),0) printf("%d\n",ans[i]);
}

Measured memory_bytes: 5124