### BUGGY CODE ###

import sys


class SegTreeSet:
    """
    bitフラグで集合を管理するセグメント木

    要素の種類数は特に明示的に与える必要は無いが、まぁ常識の範囲内で
    """

    def __init__(self, n, initial=0):
        """
        :param n: 文字列長
        :param initial: 初期値
        """
        n2 = 1 << (n - 1).bit_length()
        self.offset = n2
        self.tree = [initial] * (n2 << 1)
        self.initial = initial

    def update(self, i, x):
        """
        i番目の値にxをXOR

        :param i: index(0-indexed)
        :param x: Bit flag for operating bitwise_xor on leaf node
        """
        i += self.offset
        self.tree[i] ^= x
        while i > 1:
            self.tree[i >> 1] = self.tree[i] | self.tree[i ^ 1]
            i >>= 1

    def get_size(self, a, b):
        """
        [a, b)の要素種数を得る

        :param a: index(0-indexed)
        :param b: index(0-indexed)
        """
        result = self.initial

        l = a + self.offset
        r = b + self.offset
        while l < r:
            if r & 1:
                result |= self.tree[r - 1]
            if l & 1:
                result |= self.tree[l]
                l += 1
            l >>= 1
            r >>= 1

        return bin(result).count('1')


char_mappings = {chr(i + 97): 1 << i for i in range(26)}

n = int(input())
s = input()
s = list(s)
st = SegTreeSet(n)
for i, c in enumerate(s):
    st.update(i, char_mappings[c])
q = int(input())
ans = []
for line in sys.stdin:
    i, j, k = line.rstrip().split()
    if i == '1':
        j = int(j) - 1
        if s[j] == k:
            continue
        b = char_mappings[k] | char_mappings[s[j]]
        st.update(j, b)
        s[j] = k
    else:
        l = int(j) - 1
        r = int(k)
        ans.append(st.get_size(l, r))
print('\n'.join(map(str, ans)))


### FIXED CODE ###

import sys
from collections import defaultdict


class SegTree:
    def __init__(self, n, s):
        """
        :param n: 要素数
        :param INF: 初期値（入りうる要素より十分に大きな数）
        """
        n2 = 1 << (n - 1).bit_length()
        self.offset = n2
        self.tree = [None] * n2 + [{} for _ in range(n2)]
        self.lmd0 = lambda: 0

        for i, c in enumerate(s):
            x = ord(c) - 97
            i += self.offset
            self.tree[i][x] = 1
        for i in range(self.offset - 1, 0, -1):
            sti = self.tree[i] = defaultdict(self.lmd0, self.tree[i << 1])
            stj = self.tree[(i << 1) + 1]
            for x in stj:
                sti[x] += stj[x]
        # print(*(dict(t) for t in self.tree), sep='\n')

    def update(self, i, x):
        """
        i番目の値をxに更新
        :param i: index(0-indexed)
        :param x: update value
        """
        i += self.offset
        if x in self.tree[i]:
            return
        y, _ = self.tree[i].popitem()
        self.tree[i][x] = 1
        i >>= 1
        while i > 0:
            sti = self.tree[i]
            sti[x] += 1
            if sti[y] == 1:
                del sti[y]
            else:
                sti[y] -= 1
            i >>= 1

    def get_types(self, a, b):
        """
        [a, b)の最小値を得る
        :param a: index(0-indexed)
        :param b: index(0-indexed)
        """
        result = set()

        l = a + self.offset
        r = b + self.offset
        while l < r:
            if r & 1:
                result.update(self.tree[r - 1].keys())
            if l & 1:
                result.update(self.tree[l].keys())
                l += 1
            l >>= 1
            r >>= 1

        return len(result)


n = int(input())
s = input()
st = SegTree(n, s)
q = int(input())
ans = []
for line in sys.stdin:
    i, j, k = line.rstrip().split()
    if i == '1':
        j = int(j) - 1
        k = ord(k) - 97
        st.update(j, k)
    else:
        l = int(j) - 1
        r = int(k)
        ans.append(st.get_types(l, r))
print('\n'.join(map(str, ans)))