#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define repi(i, a, b) for(int i=(a); i>(b); i--)
#define db(x) (cerr << #x << ": " << (x) << '\n')
#define sync ios_base::sync_with_stdio(false), cin.tie(NULL)
#define cps CLOCKS_PER_SEC
#define tests(t) int t; cin >> t; while(t--)
#define iceil(n, x) (((n) + (x) - 1) / (x))
#define ll long long
#define gcd __gcd
#define eb emplace_back
#define pb push_back
#define pf push_front
#define pob pop_back
#define pof pop_front
#define sz size()
#define all(v) (v).begin(), (v).end()
#define uni(v) sort(all(v)), (v).erase(unique(all(v)), (v).end())
#define pii pair<int, int>
#define vi vector<int>
#define vpii vector<pii>
#define vvi vector<vi>
#define fi first
#define se second
#define mt make_tuple
#define pqueue priority_queue
#define bitcount(x) __builtin_popcount(x)
#define PI acos(-1.0)
#define EPS 1e-9
#define mod 1000000007
using namespace std;

#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
    cerr << name << " : " << arg1 << '\n';
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
    const char* comma = strchr(names + 1, ','); cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}

template<typename T1, typename T2>
ostream& operator << (ostream& os, const pair<T1, T2>& p) { return os << '(' << p.fi << ", " << p.se << ')'; }

template<typename T>
void printv(const T& v) { for(auto i : v) cerr << i << ' '; cerr << '\n'; }

template<typename T>
using minpq = priority_queue<T, vector<T>, greater<T>>;

template<typename T>
using maxpq = priority_queue<T>;

//All indexing is 0-based
using namespace __gnu_pbds;
template<class key, class cmp = std::less<key>>
using ordered_set = tree<key, null_type, cmp, rb_tree_tag, tree_order_statistics_node_update>;
//methods: find_by_order(k); & order_of_key(k);
//To make it an ordered_multiset, use pairs of (value, time_of_insertion)
//to distinguish values which are similar

template<class key, class value, class cmp = std::less<key>>
using ordered_map = tree<key, value, cmp, rb_tree_tag, tree_order_statistics_node_update>;

//Returns no. of values x for which ceil(n / x) == y (y must be > 1).
inline ll CC(ll n, ll y) { return iceil(n, y-1) - iceil(n, y); }

//Returns no. of values x for which floor(n / x) == y
inline ll FF(ll n, ll y) { return n / y - n / (y+1); }

//a and b are assumed to be taken modulo p
inline int add(int a, int b, int p = mod){ int c = a + b; if(c >= p) c -= p; return c; }
inline int sub(int a, int b, int p = mod){ int c = a - b; if(c < 0) c += p; return c; }
inline int mul(int a, int b, int p = mod){ return (a * 1ll * b) % p; }

#define N 500005
#define int ll
// #define trace(...) 42

const int B = 26;
int n;
int st[B][N << 2];
string s;

//Merge operation to merge the value of 2 nodes
//to produce the value at the new node
inline int op(int a, int b) {
    return a + b;
}

//Call with build(1, 0, n-1)
//Construct the tree rooted at the node no. i
//The node corresponds to the range [l, r]
void build(int st[], int b, int i, int l, int r)
{
    int m = (l + r) >> 1;
    if(l == r){
        st[i] = s[l] == b + 'a';
        return ;
    }
    
    //Recursively build the left and the right child
    int lc, rc;
    lc = i << 1;
    rc = (i << 1) | 1;
    build(st, b, lc, l, m);
    build(st, b, rc, m+1, r);
    
    //Compute the value at the current node
    st[i] = op(st[lc], st[rc]);
}

void update(int st[], int x, int val, int i, int l, int r)
{
    if(l == r){
        st[i] = val;
        return;
    }
    
    int m = (l + r) >> 1;
    int lc = i << 1, rc = (i << 1) | 1;
    
    //If x lies in the left half, recursively perform the update on the left half
    if(x <= m)
        update(st, x, val, lc, l, m);
    //Otherwise, perform the update on the right half
    else
        update(st, x, val, rc, m+1, r);
    //Compute the new value at the node
    st[i] = op(st[lc], st[rc]);
}

int query(int st[], int ql, int qr, int i, int l, int r)
{
    //Total overlap
    if(ql <= l && qr >= r)
        return st[i];
    
    //No overlap
    //if(ql > r || qr < l)
    //  return 0; //0 is specific for None as the range sum query
                  //For min, it might be inf, and for max, -inf
    
    int m = (l + r) >> 1;
    int lc = i << 1, rc = (i << 1) | 1;

    //Query range doesn't lie in the right half.
    if(qr <= m)
        return query(st, ql, qr, lc, l, m);

    //Query range doesn't lie in the left half.
    if(ql > m)
        return query(st, ql, qr, rc, m+1, r);
    
    //Recursively compute the queries over both the halves
    //and merge the results from them
    return op(query(st, ql, qr, lc, l, m), query(st, ql, qr, rc, m+1, r));
}

//Print the first num_nodes nodes of the st
/*void print_tree(int num_nodes) {
    
    for(int i=1; i<=num_nodes; i++) {
        cerr << i << ' ' << st[i] << '\n';
    }
}*/

main()
{   
    #ifdef CP
        freopen("/home/tarun/Desktop/input.txt", "r", stdin);
     // freopen("/home/tarun/Desktop/output.txt", "w", stdout);
    #endif
    sync;
    clock_t clk = clock();
    cerr << "I will return...\n";

    int q; cin >> n >> s >> q;

    rep(i, 0, B) build(st[i], i, 1, 0, n-1);

    while(q--) {
        int type; cin >> type;
        if(type == 1) {
            int i; char c; cin >> i >> c;
            --i;
            update(st[s[i]-'a'], i, 0, 1, 0, n-1);
            s[i] = c;
            update(st[s[i]-'a'], i, 1, 1, 0, n-1);
        }
        else {
            int l, r; cin >> l >> r; --l, --r;
            int ans = 0;

            rep(i, 0, B) {
                int f = query(st[i], l, r, 1, 0, n-1);
                ans += !!f;
            }

            cout << ans << '\n';
        }
    }

    cerr << "...don't you ever hang your head.\n";
    cerr << "Time (in ms): " << (double)(clock() - clk) * 1000.0 / cps << '\n';
}

//Compile using:
//g++ -o filename.exe --std=c++11 filename.cpp
//Use -D CP for defining a macro CP in the local environment




Measured memory_bytes: 267292