import sys
sys.setrecursionlimit(1 << 25)
read = sys.stdin.readline
ra = range
enu = enumerate


def read_ints():
    return list(map(int, read().split()))


def read_a_int():
    return int(read())


def read_tuple(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(tuple(map(int, read().split())))
    return ret


def read_col(H):
    '''
    H is number of rows
    A列、B列が与えられるようなとき
    ex1)A,B=read_col(H)    ex2) A,=read_col(H) #一列の場合
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return tuple(map(list, zip(*ret)))


def read_matrix(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return ret
    # return [list(map(int, read().split())) for _ in range(H)] # 内包表記はpypyでは遅いため


class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l < r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l - 1])
                l += 1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
        return res


MOD = 10**9 + 7
INF = 2**31  # 2147483648 > 10**9
# default import
from collections import defaultdict, Counter, deque
from operator import itemgetter
from itertools import product, permutations, combinations
from bisect import bisect_left, bisect_right  # , insort_left, insort_right

# https://atcoder.jp/contests/abc157/tasks/abc157_e
# 実家セグ木
# 案1 maxセグ木26本持つ(文字一つを対応させる)
# 案2 文字が出現したかしてないかを26bitの数字で表現して or 演算で区間の結果をセグ木に乗っける
# pythonだとTLEが怖いから案2で

N = read_a_int()
S = read()[:-1]
Q = read_a_int()


def char_to_26bit(c: str):
    num = ord(c) - ord('a')
    return 1 << num  # num bit目だけ1


S_num = []
for s in S:
    S_num.append(char_to_26bit(s))


def segfunc(a: int, b: int):  # 区間操作,二項演算、今だとor(少なくとも1文字がその区間に含まれている)
    return a | b


st = SegmentTree(S_num, segfunc, identity_element=0)


for _ in range(Q):
    com, *tmp = read().split()
    if com == '1':
        i, c = tmp
        st.update(int(i) - 1, char_to_26bit(c))
    else:
        l, r = map(int, tmp)
        print(bin(st.query(l - 1, r)).count('1'))  # bitの立っているところの数を数える import sys sys sys.setrecursionlimit(1 << 25) sys.setrecursionlimit sys setrecursionlimit 1 << 25 1 25 read = sys.stdin.readline read sys.stdin.readline sys.stdin sys stdin readline ra = range ra range enu = enumerate enu enumerate def read_ints():
    return list(map(int, read().split())) read_ints return list(map(int, read().split())) list(map(int, read().split())) list map(int, read().split()) map int read().split() ().split () read split def read_a_int():
    return int(read()) read_a_int return int(read()) int(read()) int read() read def read_tuple(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(tuple(map(int, read().split())))
    return ret read_tuple '''
    H is number of rows
    ''' ret = [] ret [] for _ in range(H):
        ret.append(tuple(map(int, read().split())))
     _ range(H) range H ret.append(tuple(map(int, read().split()))) ret.append ret append tuple(map(int, read().split())) tuple map(int, read().split()) map int read().split() ().split () read split return ret ret H H def read_col(H):
    '''
    H is number of rows
    A列、B列が与えられるようなとき
    ex1)A,B=read_col(H)    ex2) A,=read_col(H) #一列の場合
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return tuple(map(list, zip(*ret))) read_col '''
    H is number of rows
    A列、B列が与えられるようなとき
    ex1)A,B=read_col(H)    ex2) A,=read_col(H) #一列の場合
    ''' ret = [] ret [] for _ in range(H):
        ret.append(list(map(int, read().split())))
     _ range(H) range H ret.append(list(map(int, read().split()))) ret.append ret append list(map(int, read().split())) list map(int, read().split()) map int read().split() ().split () read split return tuple(map(list, zip(*ret))) tuple(map(list, zip(*ret))) tuple map(list, zip(*ret)) map list zip(*ret) zip *ret ret H H def read_matrix(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return ret
    # return [list(map(int, read().split())) for _ in range(H)] # 内包表記はpypyでは遅いため read_matrix '''
    H is number of rows
    ''' ret = [] ret [] for _ in range(H):
        ret.append(list(map(int, read().split())))
     _ range(H) range H ret.append(list(map(int, read().split()))) ret.append ret append list(map(int, read().split())) list map(int, read().split()) map int read().split() ().split () read split return ret ret H H class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l < r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l - 1])
                l += 1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
        return res SegmentTree def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

     __init__ '''
        セグ木
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        ''' self.ide = identity_element self.ide self ide identity_element self.func = segfunc self.func self func segfunc n = len(ls) n len(ls) len ls self.num = 2 ** (n - 1).bit_length() self.num self num 2 ** (n - 1).bit_length() 2 (n - 1).bit_length() n - 1).bit_length n - 1 n 1 bit_length self.tree = [self.ide] * (2 * self.num - 1) self.tree self tree [self.ide] * (2 * self.num - 1) [self.ide] self.ide self ide 2 * self.num - 1 2 * self.num 2 self.num self num 1 for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
         i l enumerate(ls) enumerate ls self.tree[i + self.num - 1] = l self.tree[i + self.num - 1] self.tree self tree i + self.num - 1 i + self.num i self.num self num 1 l for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

     i range(self.num - 2, -1, -1) range self.num - 2 self.num self num 2 -1 -1 self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2]) self.tree[i] self.tree self tree i segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2]) segfunc self.tree[2 * i + 1] self.tree self tree 2 * i + 1 2 * i 2 i 1 self.tree[2 * i + 2] self.tree self tree 2 * i + 2 2 * i 2 i 2 self self ls: list ls segfunc segfunc identity_element identity_element def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

     update '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        ''' i += self.num - 1 i self.num - 1 self.num self num 1 self.tree[i] = x self.tree[i] self.tree self tree i x while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

     i i = (i - 1) // 2 i (i - 1) // 2 i - 1 i 1 2 self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2]) self.tree[i] self.tree self tree i self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2]) self.func self func self.tree[i * 2 + 1] self.tree self tree i * 2 + 1 i * 2 i 2 1 self.tree[i * 2 + 2] self.tree self tree i * 2 + 2 i * 2 i 2 2 self self i i x x def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l < r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l - 1])
                l += 1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
        return res query '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        ''' if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
         r <= l r l return ValueError('invalid index (l,rがありえないよ)') ValueError('invalid index (l,rがありえないよ)') ValueError 'invalid index (l,rがありえないよ)' l += self.num l self.num self num r += self.num r self.num self num res = self.ide res self.ide self ide while l < r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l - 1])
                l += 1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
         l < r l r if l & 1:
                res = self.func(res, self.tree[l - 1])
                l += 1
             l & 1 l 1 res = self.func(res, self.tree[l - 1]) res self.func(res, self.tree[l - 1]) self.func self func res self.tree[l - 1] self.tree self tree l - 1 l 1 l += 1 l 1 if r & 1:
                r -= 1
                res = self.func(res, self.tree[r - 1])
             r & 1 r 1 r -= 1 r 1 res = self.func(res, self.tree[r - 1]) res self.func(res, self.tree[r - 1]) self.func self func res self.tree[r - 1] self.tree self tree r - 1 r 1 l >>= 1 l 1 r >>= 1 r 1 return res res self self l l r r MOD = 10**9 + 7 MOD 10**9 + 7 10**9 10 9 7 INF = 2**31 INF 2**31 2 31 from collections import defaultdict, Counter, deque from operator import itemgetter from itertools import product, permutations, combinations from bisect import bisect_left, bisect_right N = read_a_int() N read_a_int() read_a_int S = read()[:-1] S read()[:-1] () read :-1 -1 Q = read_a_int() Q read_a_int() read_a_int def char_to_26bit(c: str):
    num = ord(c) - ord('a')
    return 1 << num  # num bit目だけ1 char_to_26bit num = ord(c) - ord('a') num ord(c) - ord('a') ord(c) ord c ord('a') ord 'a' return 1 << num 1 << num 1 num c: str c S_num = [] S_num [] for s in S:
    S_num.append(char_to_26bit(s)) s S S_num.append(char_to_26bit(s)) S_num.append S_num append char_to_26bit(s) char_to_26bit s def segfunc(a: int, b: int):  # 区間操作,二項演算、今だとor(少なくとも1文字がその区間に含まれている)
    return a | b segfunc return a | b a | b a b a: int a b: int b st = SegmentTree(S_num, segfunc, identity_element=0) st SegmentTree(S_num, segfunc, identity_element=0) SegmentTree S_num segfunc identity_element=0 identity_element 0 for _ in range(Q):
    com, *tmp = read().split()
    if com == '1':
        i, c = tmp
        st.update(int(i) - 1, char_to_26bit(c))
    else:
        l, r = map(int, tmp)
        print(bin(st.query(l - 1, r)).count('1'))  # bitの立っているところの数を数える _ range(Q) range Q com, *tmp = read().split() com read().split() ().split () read split *tmp tmp if com == '1':
        i, c = tmp
        st.update(int(i) - 1, char_to_26bit(c))
    else:
        l, r = map(int, tmp)
        print(bin(st.query(l - 1, r)).count('1'))  # bitの立っているところの数を数える com == '1' com '1' i, c = tmp i tmp c st.update(int(i) - 1, char_to_26bit(c)) st.update st update int(i) - 1 int(i) int i 1 char_to_26bit(c) char_to_26bit c l, r = map(int, tmp) l map(int, tmp) map int tmp r print(bin(st.query(l - 1, r)).count('1')) print bin(st.query(l - 1, r)).count('1') (st.query(l - 1, r)).count (st.query(l - 1, r)) bin st.query(l - 1, r) st.query st query l - 1 l 1 r count '1' S = read()[:-1] read()[:-1] S MOD = 10**9 + 7 10**9 + 7 MOD INF = 2**31 2**31 INF enu = enumerate enumerate enu def read_ints():
    return list(map(int, read().split())) def read_ints():
    return list(map(int, read().split())) read_ints i, c = tmp tmp i def char_to_26bit(c: str):
    num = ord(c) - ord('a')
    return 1 << num  # num bit目だけ1 def char_to_26bit(c: str):
    num = ord(c) - ord('a')
    return 1 << num  # num bit目だけ1 char_to_26bit r = map(int, tmp) map(int, tmp) r c = tmp tmp c read = sys.stdin.readline sys.stdin.readline read ra = range range ra def read_matrix(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return ret
    # return [list(map(int, read().split())) for _ in range(H)] # 内包表記はpypyでは遅いため def read_matrix(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return ret
    # return [list(map(int, read().split())) for _ in range(H)] # 内包表記はpypyでは遅いため read_matrix Q = read_a_int() read_a_int() Q S_num = [] [] S_num l, r = map(int, tmp) map(int, tmp) l def read_a_int():
    return int(read()) def read_a_int():
    return int(read()) read_a_int st = SegmentTree(S_num, segfunc, identity_element=0) SegmentTree(S_num, segfunc, identity_element=0) st com, *tmp = read().split() read().split() com class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l < r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l - 1])
                l += 1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
        return res class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l < r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l - 1])
                l += 1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
        return res SegmentTree N = read_a_int() read_a_int() N def segfunc(a: int, b: int):  # 区間操作,二項演算、今だとor(少なくとも1文字がその区間に含まれている)
    return a | b def segfunc(a: int, b: int):  # 区間操作,二項演算、今だとor(少なくとも1文字がその区間に含まれている)
    return a | b segfunc def read_col(H):
    '''
    H is number of rows
    A列、B列が与えられるようなとき
    ex1)A,B=read_col(H)    ex2) A,=read_col(H) #一列の場合
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return tuple(map(list, zip(*ret))) def read_col(H):
    '''
    H is number of rows
    A列、B列が与えられるようなとき
    ex1)A,B=read_col(H)    ex2) A,=read_col(H) #一列の場合
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return tuple(map(list, zip(*ret))) read_col def read_tuple(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(tuple(map(int, read().split())))
    return ret def read_tuple(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(tuple(map(int, read().split())))
    return ret read_tuple
import sys
sys.setrecursionlimit(1 << 25)
read = sys.stdin.readline
ra = range
enu = enumerate


def read_ints():
    return list(map(int, read().split()))


def read_a_int():
    return int(read())


def read_tuple(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(tuple(map(int, read().split())))
    return ret


def read_col(H):
    '''
    H is number of rows
    A列、B列が与えられるようなとき
    ex1)A,B=read_col(H)    ex2) A,=read_col(H) #一列の場合
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return tuple(map(list, zip(*ret)))


def read_matrix(H):
    '''
    H is number of rows
    '''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, read().split())))
    return ret
    # return [list(map(int, read().split())) for _ in range(H)] # 内包表記はpypyでは遅いため


class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l < r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l - 1])
                l += 1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
        return res


MOD = 10**9 + 7
INF = 2**31  # 2147483648 > 10**9
# default import
from collections import defaultdict, Counter, deque
from operator import itemgetter
from itertools import product, permutations, combinations
from bisect import bisect_left, bisect_right  # , insort_left, insort_right

# https://atcoder.jp/contests/abc157/tasks/abc157_e
# 実家セグ木
# 案1 maxセグ木26本持つ(文字一つを対応させる)
# 案2 文字が出現したかしてないかを26bitの数字で表現して or 演算で区間の結果をセグ木に乗っける
# pythonだとTLEが怖いから案2で

N = read_a_int()
S = read()[:-1]
Q = read_a_int()


def char_to_26bit(c: str):
    num = ord(c) - ord('a')
    return 1 << num  # num bit目だけ1


S_num = []
for s in S:
    S_num.append(char_to_26bit(s))


def segfunc(a: int, b: int):  # 区間操作,二項演算、今だとor(少なくとも1文字がその区間に含まれている)
    return a | b


st = SegmentTree(S_num, segfunc, identity_element=0)


for _ in range(Q):
    com, *tmp = read().split()
    if com == '1':
        i, c = tmp
        st.update(int(i) - 1, char_to_26bit(c))
    else:
        l, r = map(int, tmp)
        print(bin(st.query(l - 1, r)).count('1'))  # bitの立っているところの数を数える
