#include <bits/stdc++.h>
using namespace std;

#define CPP_STR(x) CPP_STR_I(x)
#define CPP_CAT(x,y) CPP_CAT_I(x,y)
#define CPP_STR_I(args...) #args
#define CPP_CAT_I(x,y) x ## y

using i8  = int8_t;
using u8  = uint8_t;
using i16 = int16_t;
using u16 = uint16_t;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;

using f32 = float;
using f64 = double;

#define FOR(i, start, end) for(i64 i = (start), CPP_CAT(i,xxxx_end)=(end); i < CPP_CAT(i,xxxx_end); ++i)
#define REP(i, n) FOR(i, 0, n)
#define REPS(i, n) for(i64 i = 1; i <= n; ++i)
#define RREP(i, n) for(i64 i = n - 1; i >= 0 ; --i)
#define RREPS(i, n) for(i64 i = n; i >= 1; --i)

#define ALL(f,c,...) (([&](decltype((c)) cccc) { return (f)(std::begin(cccc), std::end(cccc), ## __VA_ARGS__); })(c))

#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

#define pb push_back
#define mp make_pair
#define F first
#define S second

template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }

template<typename C>
i64 SIZE(const C& c) { return static_cast<i64>(c.size()); }

template<typename T, size_t N>
i64 SIZE(const T (&)[N]) { return static_cast<i64>(N); }


struct ProconInit {
    static constexpr int IOS_PREC = 15;
    static constexpr bool AUTOFLUSH = false;

    ProconInit() {
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(IOS_PREC);
        if(AUTOFLUSH)
            cout << unitbuf;
    }
} PROCON_INIT;


template<typename Monoid>
struct SegmentTree {
    using F = function<Monoid(Monoid, Monoid)>;

    i64 sz;
    vector<Monoid> seg;

    const F f;
    const Monoid M1;

    SegmentTree(i64 n, const F f, const Monoid &M1) : f(f), M1(M1) {
        sz = 1;
        while (sz < n) sz *= 2;
        seg.assign(2 * sz - 1, M1);
    }

    void set(i64 k, const Monoid &x) {
        seg[k + sz - 1] = x;
    }

    void build() {
        for (i64 k = sz - 2; k >= 0; k--) {
            seg[k] = f(seg[2 * k + 1], seg[2 * k + 2]);
        }
    }

    void update(i64 k, const Monoid &x) {
        k += sz - 1;
        seg[k] = x;
        while (k > 0) {
            k = (k - 1) / 2;
            seg[k] = f(seg[2 * k + 1], seg[2 * k + 2]);
        }
    }

    Monoid query(i64 l, i64 r) {
        Monoid vl = M1, vr = M1;
        for (l += sz - 1, r += sz - 1; l < r; l = (l - 1) / 2, r = (r - 1) / 2) {
            if ((l & 1) == 0) vl = f(vl, seg[l++]);
            if ((r & 1) == 0) vr = f(seg[--r], vr);
        }
        return f(vl, vr);
    }

    Monoid operator[](const i64 &k) const {
        return seg[k + sz - 1];
    }
};


#define MAX_N 200'000
i64 N, Q;
string s;

i64 ctob(char c) {
    return 1 << (c - 'a');
}

int main() {
    cin >> N >> s >> Q;

    SegmentTree<i64> segtree(N, [](i64 x, i64 y){ return x | y; }, 0);

    REP(i, s.length()) {
        segtree.set(i, ctob(s[i]));
    }
    segtree.build();

    i64 t, k, l, r;
    char c;
    REP(i, Q) {
        cin >> t;
        if (t == 1) {
            cin >> k >> c;
            k--;
            segtree.update(k, ctob(c));
        } else {
            cin >> l >> r;
            l--; r--;
            i64 cset = segtree.query(l, r + 1);
            cout << __builtin_popcount(cset) << endl;
        }
    }

    return 0;
}

Measured memory_bytes: 9116