# Binary Indexed Treeを各アルファベットについてもつ (それぞれN+1の空間を保持し、1-indexで考える)

N = int(eval(input()))

S = list(eval(input()))

BITS = [[0]*(N+1) for _ in range(26)]

# 初期化を行おうと思ったが、これ自体に関数が必要である

# 値の加算





def ctoi(alphabet):

    return ord(alphabet)-97





# 1~idxまでの文字に各文字がどれだけ出現するか

def BIT_query(idx):

    res = [0]*26

    for i in range(26):

        p = idx

        tmp = 0

        while p > 0:

            tmp += BITS[i][p]

            p -= p & (-p)

        res[i] = tmp

    return res





def BIT_update(idx, alphabet, x):  # idx: int, alphabet: str, x: int

    while idx <= N:

        BITS[ctoi(alphabet)][idx] += x

        idx += idx&(-idx)





# 初期化を行う

for i in range(N):

    BIT_update(i+1, S[i], 1)



# クエリを受け取っていく

Q = int(eval(input()))

for _ in range(Q):

    type, a, b = list(map(str, input().split()))

    if type == "1":  # 更新のクエリなら

        # このとき、aはindex, bは変更後の文字(str)である

        a = int(a)

        if S[a-1] == b:

            continue

        BIT_update(a, S[a-1], -1)  # 減らす処理

        BIT_update(a, b, 1)  # 増やす処理

        S[a-1] = b

    elif type == "2":  # 回答する必要があるクエリ

        # このとき、aは左端, bは右端

        a, b = int(a), int(b)

        cnt1 = BIT_query(a-1)

        cnt2 = BIT_query(b)

        ans = 0

        for i in range(26):

            if cnt2[i] > cnt1[i]:

                ans += 1

        print(ans)

"""segfunc"""





# 論理和を返す

def segfunc(x, y):

    return x | y





def init(init_val):

    # set_val

    for i in range(N):

        seg[i-1+num] = init_val[i]



    # built

    for i in range(num-2, -1, -1):  # 木の下の方から埋めていく, nではなくnumであることに注意

        seg[i] = segfunc(seg[2*i+1], seg[2*i+2])  # 子のインデックス





# 更新

def update(k, x):

    k += num-1  # 場所kに対するseg木の葉のindex?

    seg[k] = x

    while k:

        k = (k-1)//2  # 親のノードのindexを取得

        seg[k] = segfunc(seg[2*k+1], seg[2*k+2])





def query(p, q):

    if q <= p:  # 半開区間なので、等しくてもアウト？

        return ide_ele

    p += num-1

    q += num-2  # 半開区間なので、q側を-2している？

    res = ide_ele

    while q-p > 1:

        if p % 2 == 0:

            res = segfunc(res, seg[p])

        if q % 2 == 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





# 単位元

ide_ele = 0



N = int(eval(input()))

ss = list(eval(input()))

s = []

for i in range(N):

    s.append(1<<(ord(ss[i]))-97)



# num: n以上の最小の2のベキ乗

num = 2**(N-1).bit_length()

seg = [ide_ele]*2*num



init(s)





def popcnt(n):

    c = (n & 0x5555555555555555) + ((n>>1) & 0x5555555555555555)

    c = (c & 0x3333333333333333) + ((c>>2) & 0x3333333333333333)

    c = (c & 0x0f0f0f0f0f0f0f0f) + ((c>>4) & 0x0f0f0f0f0f0f0f0f)

    c = (c & 0x00ff00ff00ff00ff) + ((c>>8) & 0x00ff00ff00ff00ff)

    c = (c & 0x0000ffff0000ffff) + ((c>>16) & 0x0000ffff0000ffff)

    c = (c & 0x00000000ffffffff) + ((c>>32) & 0x00000000ffffffff)

    return c





q = int(eval(input()))

for i in range(q):

    qq, xx, yy = list(map(str, input().split()))

    if qq == '1':

        xx = int(xx)

        update(xx-1,1<<(ord(yy)-97))

    else:

        xx, yy = int(xx), int(yy)

        res = query(xx-1,yy)

        print((popcnt(res)))

# Binary Indexed Treeを各アルファベットについてもつ (それぞれN+1の空間を保持し、1-indexで考える)
N = int(eval(input()))
S = list(eval(input()))
BITS = [[0] * (N + 1) for _ in range(26)]
# 初期化を行おうと思ったが、これ自体に関数が必要である
# 値の加算
def ctoi(alphabet):
    return ord(alphabet) - 97


# 1~idxまでの文字に各文字がどれだけ出現するか
def BIT_query(idx):
    res = [0] * 26
    for i in range(26):
        p = idx
        tmp = 0
        while p > 0:
            tmp += BITS[i][p]
            p -= p & (-p)
        res[i] = tmp
    return res


def BIT_update(idx, alphabet, x):  # idx: int, alphabet: str, x: int
    while idx <= N:
        BITS[ctoi(alphabet)][idx] += x
        idx += idx & (-idx)


# 初期化を行う
for i in range(N):
    BIT_update(i + 1, S[i], 1)
# クエリを受け取っていく
Q = int(eval(input()))
for _ in range(Q):
    type, a, b = list(map(str, input().split()))
    if type == "1":  # 更新のクエリなら
        # このとき、aはindex, bは変更後の文字(str)である
        a = int(a)
        if S[a - 1] == b:
            continue
        BIT_update(a, S[a - 1], -1)  # 減らす処理
        BIT_update(a, b, 1)  # 増やす処理
        S[a - 1] = b
    elif type == "2":  # 回答する必要があるクエリ
        # このとき、aは左端, bは右端
        a, b = int(a), int(b)
        cnt1 = BIT_query(a - 1)
        cnt2 = BIT_query(b)
        ans = 0
        for i in range(26):
            if cnt2[i] > cnt1[i]:
                ans += 1
        print(ans)

"""segfunc"""
# 論理和を返す
def segfunc(x, y):
    return x | y


def init(init_val):
    # set_val
    for i in range(N):
        seg[i - 1 + num] = init_val[i]
    # built
    for i in range(num - 2, -1, -1):  # 木の下の方から埋めていく, nではなくnumであることに注意
        seg[i] = segfunc(seg[2 * i + 1], seg[2 * i + 2])  # 子のインデックス


# 更新
def update(k, x):
    k += num - 1  # 場所kに対するseg木の葉のindex?
    seg[k] = x
    while k:
        k = (k - 1) // 2  # 親のノードのindexを取得
        seg[k] = segfunc(seg[2 * k + 1], seg[2 * k + 2])


def query(p, q):
    if q <= p:  # 半開区間なので、等しくてもアウト？
        return ide_ele
    p += num - 1
    q += num - 2  # 半開区間なので、q側を-2している？
    res = ide_ele
    while q - p > 1:
        if p % 2 == 0:
            res = segfunc(res, seg[p])
        if q % 2 == 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


# 単位元
ide_ele = 0
N = int(eval(input()))
ss = list(eval(input()))
s = []
for i in range(N):
    s.append(1 << (ord(ss[i])) - 97)
# num: n以上の最小の2のベキ乗
num = 2 ** (N - 1).bit_length()
seg = [ide_ele] * 2 * num
init(s)


def popcnt(n):
    c = (n & 0x5555555555555555) + ((n >> 1) & 0x5555555555555555)
    c = (c & 0x3333333333333333) + ((c >> 2) & 0x3333333333333333)
    c = (c & 0x0F0F0F0F0F0F0F0F) + ((c >> 4) & 0x0F0F0F0F0F0F0F0F)
    c = (c & 0x00FF00FF00FF00FF) + ((c >> 8) & 0x00FF00FF00FF00FF)
    c = (c & 0x0000FFFF0000FFFF) + ((c >> 16) & 0x0000FFFF0000FFFF)
    c = (c & 0x00000000FFFFFFFF) + ((c >> 32) & 0x00000000FFFFFFFF)
    return c


q = int(eval(input()))
for i in range(q):
    qq, xx, yy = list(map(str, input().split()))
    if qq == "1":
        xx = int(xx)
        update(xx - 1, 1 << (ord(yy) - 97))
    else:
        xx, yy = int(xx), int(yy)
        res = query(xx - 1, yy)
        print((popcnt(res)))

-# Binary Indexed Treeを各アルファベットについてもつ (それぞれN+1の空間を保持し、1-indexで考える) -N = int(eval(input())) -S = list(eval(input())) -BITS = [[0] * (N + 1) for _ in range(26)] -# 初期化を行おうと思ったが、これ自体に関数が必要である -# 値の加算 -def ctoi(alphabet): -    return ord(alphabet) - 97 +"""segfunc""" +# 論理和を返す +def segfunc(x, y): +    return x | y -# 1~idxまでの文字に各文字がどれだけ出現するか -def BIT_query(idx): -    res = [0] * 26 -    for i in range(26): -        p = idx -        tmp = 0 -        while p > 0: -            tmp += BITS[i][p] -            p -= p & (-p) -        res[i] = tmp +def init(init_val): +    # set_val +    for i in range(N): +        seg[i - 1 + num] = init_val[i] +    # built +    for i in range(num - 2, -1, -1):  # 木の下の方から埋めていく, nではなくnumであることに注意 +        seg[i] = segfunc(seg[2 * i + 1], seg[2 * i + 2])  # 子のインデックス + + +# 更新 +def update(k, x): +    k += num - 1  # 場所kに対するseg木の葉のindex? +    seg[k] = x +    while k: +        k = (k - 1) // 2  # 親のノードのindexを取得 +        seg[k] = segfunc(seg[2 * k + 1], seg[2 * k + 2]) + + +def query(p, q): +    if q <= p:  # 半開区間なので、等しくてもアウト？ +        return ide_ele +    p += num - 1 +    q += num - 2  # 半開区間なので、q側を-2している？ +    res = ide_ele +    while q - p > 1: +        if p % 2 == 0: +            res = segfunc(res, seg[p]) +        if q % 2 == 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]) -def BIT_update(idx, alphabet, x):  # idx: int, alphabet: str, x: int -    while idx <= N: -        BITS[ctoi(alphabet)][idx] += x -        idx += idx & (-idx) +# 単位元 +ide_ele = 0 +N = int(eval(input())) +ss = list(eval(input())) +s = [] +for i in range(N): +    s.append(1 << (ord(ss[i])) - 97) +# num: n以上の最小の2のベキ乗 +num = 2 ** (N - 1).bit_length() +seg = [ide_ele] * 2 * num +init(s) -# 初期化を行う -for i in range(N): -    BIT_update(i + 1, S[i], 1) -# クエリを受け取っていく -Q = int(eval(input())) -for _ in range(Q): -    type, a, b = list(map(str, input().split())) -    if type == "1":  # 更新のクエリなら -        # このとき、aはindex, bは変更後の文字(str)である -        a = int(a) -        if S[a - 1] == b: -            continue -        BIT_update(a, S[a - 1], -1)  # 減らす処理 -        BIT_update(a, b, 1)  # 増やす処理 -        S[a - 1] = b -    elif type == "2":  # 回答する必要があるクエリ -        # このとき、aは左端, bは右端 -        a, b = int(a), int(b) -        cnt1 = BIT_query(a - 1) -        cnt2 = BIT_query(b) -        ans = 0 -        for i in range(26): -            if cnt2[i] > cnt1[i]: -                ans += 1 -        print(ans) +def popcnt(n): +    c = (n & 0x5555555555555555) + ((n >> 1) & 0x5555555555555555) +    c = (c & 0x3333333333333333) + ((c >> 2) & 0x3333333333333333) +    c = (c & 0x0F0F0F0F0F0F0F0F) + ((c >> 4) & 0x0F0F0F0F0F0F0F0F) +    c = (c & 0x00FF00FF00FF00FF) + ((c >> 8) & 0x00FF00FF00FF00FF) +    c = (c & 0x0000FFFF0000FFFF) + ((c >> 16) & 0x0000FFFF0000FFFF) +    c = (c & 0x00000000FFFFFFFF) + ((c >> 32) & 0x00000000FFFFFFFF) +    return c + + +q = int(eval(input())) +for i in range(q): +    qq, xx, yy = list(map(str, input().split())) +    if qq == "1": +        xx = int(xx) +        update(xx - 1, 1 << (ord(yy) - 97)) +    else: +        xx, yy = int(xx), int(yy) +        res = query(xx - 1, yy) +        print((popcnt(res)))