### BUGGY CODE ###

def main():
    N = int(input())
    S = list(input())

    c = lambda x: ord(x) - ord('a')
    tree = [SegmentTree(N, lambda x,y:x|y) for _ in range(26)]
    for i, l in enumerate(S):
        tree[c(l)].update(i, 1)

    Q = int(input())
    for _ in range(Q):
        t, a, b = input().split()
        if t == '1':
            a = int(a) - 1
            tree[c(S[a])].update(a, 0)
            tree[c(b)].update(a, 1)
            S[a] = b
        else:
            a, b = int(a)-1, int(b)-1
            ans = 0
            for i in range(26):
                t = tree[i].query(a, b+1)
                ans += 1 if t else 0
            print(ans)

class SegmentTree:
    def __init__(self, n=None, f=max, zero_factory=int, initial_values=None):
        assert(n, initial_values)
        size = n if n else len(initial_values)
        self.__f, self.__z, = f, zero_factory
        self.__n = 1 << ((size - 1).bit_length())
        self.__dat = [zero_factory() for _ in range(2 * self.__n)]
        if initial_values:
            zi = self.__get_leaf(0)
            for i, v in enumerate(initial_values): self.__dat[zi + i] = v
            for i in range(zi-1, -1, -1): self.__dat[i] = f(*self.__get_children(i))

    def update(self, index, value):
        i, v = self.__get_leaf(index), value
        if self.__dat[i] == v: return
        self.__dat[i] = v
        while i:
            i = self.__get_parent(i)
            self.__dat[i] = self.__f(*self.__get_children(i))

    def query(self, from_inclusive, to_exclusive):
        ans = self.__z()
        if to_exclusive <= from_inclusive: return ans
        l, r = self.__get_leaf(from_inclusive), self.__get_leaf(to_exclusive) - 1
        while r - l > 1:
            if self.__is_right(l): ans = self.__f(ans, self.__dat[l])
            if self.__is_left(r): ans, r = self.__f(ans, self.__dat[r]), r-1
            l, r = l//2, self.__get_parent(r)
        ans = self.__f(ans, self.__dat[l])
        if l != r: ans = self.__f(ans, self.__dat[r])
        return ans

    def __get_leaf(self, i): return self.__n + i - 1
    def __get_parent(self, i): return (i-1)//2
    def __get_children(self, i): return (self.__dat[2*i+1], self.__dat[2*i+2])
    def __is_left(self, i): return i&1 == 1
    def __is_right(self, i): return i&1 == 0

if __name__ == '__main__':
    main()


### FIXED CODE ###

import sys
input = sys.stdin.readline
N = int(input())
S = input()
Q = int(input())

ide_ele = 0

def segfunc(x,y):
    return x|y

def init(init_val):
    #set_val
    for i in range(N):
        seg[i+num-1]=1<<(ord(init_val[i])-ord('a'))
    #built
    for i in range(num-2,-1,-1) :
        seg[i]=segfunc(seg[2*i+1],seg[2*i+2]) 
    
def update(k,x):
    k += num-1
    x = 1<<(ord(x)-ord('a'))
    if x == seg[k]: return
    seg[k] = x
    while k:
        k = (k-1)//2
        seg[k] = segfunc(seg[k*2+1],seg[k*2+2])
    
def query(p,q):
    if q<=p:
        return ide_ele
    p += num-1
    q += num-2
    res=ide_ele
    while q-p>1:
        if p&1 == 0:
            res = segfunc(res,seg[p])
        if q&1 == 1:
            res = segfunc(res,seg[q])
            q -= 1
        p = p//2
        q = (q-1)//2
    if p == q:
        res = segfunc(res,seg[p])
    else:
        res = segfunc(segfunc(res,seg[p]),seg[q])
    return res

#num:n以上の最小の2のべき乗
num =2**(N-1).bit_length()
seg=[ide_ele]*2*num

init(S)

for _ in range(Q):
    t, a, b = input().split()
    if t == '1':
        a = int(a)
        update(a-1, b)
    else:
        a, b = int(a)-1, int(b)
        print(bin(query(a,b)).count('1'))