import sys
import math
import string
import fractions
import random
from operator import itemgetter
import itertools
from collections import deque
import copy
import heapq
import bisect

MOD = 10 ** 9 + 7
INF = float('inf')
input = lambda: sys.stdin.readline().strip()


def func(a, b):
    if a | b == 0:
        return 0
    else:
        return 1


class SegmentTree:
    """
    各ノードが半開区間に対応した完全二分木。
    子は親を半分にした区間を持つ。
    構築O(n), 区間に対する操作O(logn), 値の更新O(logn)
    区間に対する操作は最小値, 最大値, 区間に対する和など柔軟に変更して用いよう！
    """

    def __init__(self, x, init_val):  # 構築, init_valは配列の初期値
        self.init_val = init_val
        self.length = 2 ** ((len(x) - 1).bit_length())
        self.data = [init_val] * 2 * self.length
        for i in range(len(x)):
            self.data[i + self.length - 1] = x[i]
        for i in range(self.length - 2, -1, -1):
            self.data[i] = func(self.data[2 * i + 1], self.data[2 * i + 2])

    def teach_current_val(self, index):
        return self.data[index + self.length - 1]

    def replace(self, index, val):  # indexの値をvalに更新
        index += self.length - 1
        self.data[index] = val
        while index:
            index = (index - 1) // 2
            self.data[index] = func(self.data[2 * index + 1], self.data[2 * index + 2])

    def query(self, left, right):  # 半開区間の最小値等を求める, 葉からさかのぼっていくイメージ。
        if right <= left:
            return self.init_val
        left += self.length - 1  # self.dataの位置に合わせる。
        right += self.length - 2  # self.dataの位置に合わせる。半開区間
        ans_ = self.init_val
        while right > left + 1:
            if left & 1 == 0:  # if left_index%2 == 0:
                ans_ = func(ans_, self.data[left])
            if right & 1 == 1:  # if right_index%2 == 1:
                ans_ = func(ans_, self.data[right])
                right -= 1
            left //= 2
            right = (right - 1) // 2
        if left == right:
            ans_ = func(ans_, self.data[left])
        else:
            ans_ = func(func(ans_, self.data[left]), self.data[right])
        return ans_


N = int(input())
S = input()
Q = int(input())
alphabets = string.ascii_lowercase
segs = []
check = dict()
for i in alphabets:
    segs.append([1 if S[l] == i else 0 for l in range(N)])
for i in range(26):
    segs[i] = SegmentTree(segs[i], 0)
for _ in range(Q):
    Query = list(map(str, input().split()))
    if Query[0] == "1":
        i, c = int(Query[1]), Query[2]
        if check.get(str(i - 1)):
            segs[ord(check[str(i - 1)]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
        else:
            segs[ord(S[i - 1]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
    else:
        l, r = map(int, (Query[1], Query[2]))
        ans = 0
        for i in segs:
            ans += i.query(l - 1, r)
        print(ans) import sys sys import math math import string string import fractions fractions import random random from operator import itemgetter import itertools itertools from collections import deque import copy copy import heapq heapq import bisect bisect MOD = 10 ** 9 + 7 MOD 10 ** 9 + 7 10 ** 9 10 9 7 INF = float('inf') INF float('inf') float 'inf' input = lambda: sys.stdin.readline().strip() input lambda: sys.stdin.readline().strip() sys.stdin.readline().strip() sys.stdin.readline().strip sys.stdin.readline() sys.stdin.readline sys.stdin sys stdin readline strip def func(a, b):
    if a | b == 0:
        return 0
    else:
        return 1 func if a | b == 0:
        return 0
    else:
        return 1 a | b == 0 a | b a b 0 return 0 0 return 1 1 a a b b class SegmentTree:
    """
    各ノードが半開区間に対応した完全二分木。
    子は親を半分にした区間を持つ。
    構築O(n), 区間に対する操作O(logn), 値の更新O(logn)
    区間に対する操作は最小値, 最大値, 区間に対する和など柔軟に変更して用いよう！
    """

    def __init__(self, x, init_val):  # 構築, init_valは配列の初期値
        self.init_val = init_val
        self.length = 2 ** ((len(x) - 1).bit_length())
        self.data = [init_val] * 2 * self.length
        for i in range(len(x)):
            self.data[i + self.length - 1] = x[i]
        for i in range(self.length - 2, -1, -1):
            self.data[i] = func(self.data[2 * i + 1], self.data[2 * i + 2])

    def teach_current_val(self, index):
        return self.data[index + self.length - 1]

    def replace(self, index, val):  # indexの値をvalに更新
        index += self.length - 1
        self.data[index] = val
        while index:
            index = (index - 1) // 2
            self.data[index] = func(self.data[2 * index + 1], self.data[2 * index + 2])

    def query(self, left, right):  # 半開区間の最小値等を求める, 葉からさかのぼっていくイメージ。
        if right <= left:
            return self.init_val
        left += self.length - 1  # self.dataの位置に合わせる。
        right += self.length - 2  # self.dataの位置に合わせる。半開区間
        ans_ = self.init_val
        while right > left + 1:
            if left & 1 == 0:  # if left_index%2 == 0:
                ans_ = func(ans_, self.data[left])
            if right & 1 == 1:  # if right_index%2 == 1:
                ans_ = func(ans_, self.data[right])
                right -= 1
            left //= 2
            right = (right - 1) // 2
        if left == right:
            ans_ = func(ans_, self.data[left])
        else:
            ans_ = func(func(ans_, self.data[left]), self.data[right])
        return ans_ SegmentTree """
    各ノードが半開区間に対応した完全二分木。
    子は親を半分にした区間を持つ。
    構築O(n), 区間に対する操作O(logn), 値の更新O(logn)
    区間に対する操作は最小値, 最大値, 区間に対する和など柔軟に変更して用いよう！
    """ def __init__(self, x, init_val):  # 構築, init_valは配列の初期値
        self.init_val = init_val
        self.length = 2 ** ((len(x) - 1).bit_length())
        self.data = [init_val] * 2 * self.length
        for i in range(len(x)):
            self.data[i + self.length - 1] = x[i]
        for i in range(self.length - 2, -1, -1):
            self.data[i] = func(self.data[2 * i + 1], self.data[2 * i + 2])

     __init__ self.init_val = init_val self.init_val self init_val init_val self.length = 2 ** ((len(x) - 1).bit_length()) self.length self length 2 ** ((len(x) - 1).bit_length()) 2 (len(x) - 1).bit_length() len(x) - 1).bit_length len(x) - 1 len(x) len x 1 bit_length self.data = [init_val] * 2 * self.length self.data self data [init_val] * 2 * self.length [init_val] * 2 [init_val] init_val 2 self.length self length for i in range(len(x)):
            self.data[i + self.length - 1] = x[i]
         i range(len(x)) range len(x) len x self.data[i + self.length - 1] = x[i] self.data[i + self.length - 1] self.data self data i + self.length - 1 i + self.length i self.length self length 1 x[i] x i for i in range(self.length - 2, -1, -1):
            self.data[i] = func(self.data[2 * i + 1], self.data[2 * i + 2])

     i range(self.length - 2, -1, -1) range self.length - 2 self.length self length 2 -1 -1 self.data[i] = func(self.data[2 * i + 1], self.data[2 * i + 2]) self.data[i] self.data self data i func(self.data[2 * i + 1], self.data[2 * i + 2]) func self.data[2 * i + 1] self.data self data 2 * i + 1 2 * i 2 i 1 self.data[2 * i + 2] self.data self data 2 * i + 2 2 * i 2 i 2 self self x x init_val init_val def teach_current_val(self, index):
        return self.data[index + self.length - 1]

     teach_current_val return self.data[index + self.length - 1] self.data[index + self.length - 1] self.data self data index + self.length - 1 index + self.length index self.length self length 1 self self index index def replace(self, index, val):  # indexの値をvalに更新
        index += self.length - 1
        self.data[index] = val
        while index:
            index = (index - 1) // 2
            self.data[index] = func(self.data[2 * index + 1], self.data[2 * index + 2])

     replace index += self.length - 1 index self.length - 1 self.length self length 1 self.data[index] = val self.data[index] self.data self data index val while index:
            index = (index - 1) // 2
            self.data[index] = func(self.data[2 * index + 1], self.data[2 * index + 2])

     index index = (index - 1) // 2 index (index - 1) // 2 index - 1 index 1 2 self.data[index] = func(self.data[2 * index + 1], self.data[2 * index + 2]) self.data[index] self.data self data index func(self.data[2 * index + 1], self.data[2 * index + 2]) func self.data[2 * index + 1] self.data self data 2 * index + 1 2 * index 2 index 1 self.data[2 * index + 2] self.data self data 2 * index + 2 2 * index 2 index 2 self self index index val val def query(self, left, right):  # 半開区間の最小値等を求める, 葉からさかのぼっていくイメージ。
        if right <= left:
            return self.init_val
        left += self.length - 1  # self.dataの位置に合わせる。
        right += self.length - 2  # self.dataの位置に合わせる。半開区間
        ans_ = self.init_val
        while right > left + 1:
            if left & 1 == 0:  # if left_index%2 == 0:
                ans_ = func(ans_, self.data[left])
            if right & 1 == 1:  # if right_index%2 == 1:
                ans_ = func(ans_, self.data[right])
                right -= 1
            left //= 2
            right = (right - 1) // 2
        if left == right:
            ans_ = func(ans_, self.data[left])
        else:
            ans_ = func(func(ans_, self.data[left]), self.data[right])
        return ans_ query if right <= left:
            return self.init_val
         right <= left right left return self.init_val self.init_val self init_val left += self.length - 1 left self.length - 1 self.length self length 1 right += self.length - 2 right self.length - 2 self.length self length 2 ans_ = self.init_val ans_ self.init_val self init_val while right > left + 1:
            if left & 1 == 0:  # if left_index%2 == 0:
                ans_ = func(ans_, self.data[left])
            if right & 1 == 1:  # if right_index%2 == 1:
                ans_ = func(ans_, self.data[right])
                right -= 1
            left //= 2
            right = (right - 1) // 2
         right > left + 1 right left + 1 left 1 if left & 1 == 0:  # if left_index%2 == 0:
                ans_ = func(ans_, self.data[left])
             left & 1 == 0 left & 1 left 1 0 ans_ = func(ans_, self.data[left]) ans_ func(ans_, self.data[left]) func ans_ self.data[left] self.data self data left if right & 1 == 1:  # if right_index%2 == 1:
                ans_ = func(ans_, self.data[right])
                right -= 1
             right & 1 == 1 right & 1 right 1 1 ans_ = func(ans_, self.data[right]) ans_ func(ans_, self.data[right]) func ans_ self.data[right] self.data self data right right -= 1 right 1 left //= 2 left 2 right = (right - 1) // 2 right (right - 1) // 2 right - 1 right 1 2 if left == right:
            ans_ = func(ans_, self.data[left])
        else:
            ans_ = func(func(ans_, self.data[left]), self.data[right])
         left == right left right ans_ = func(ans_, self.data[left]) ans_ func(ans_, self.data[left]) func ans_ self.data[left] self.data self data left ans_ = func(func(ans_, self.data[left]), self.data[right]) ans_ func(func(ans_, self.data[left]), self.data[right]) func func(ans_, self.data[left]) func ans_ self.data[left] self.data self data left self.data[right] self.data self data right return ans_ ans_ self self left left right right N = int(input()) N int(input()) int input() input S = input() S input() input Q = int(input()) Q int(input()) int input() input alphabets = string.ascii_lowercase alphabets string.ascii_lowercase string ascii_lowercase segs = [] segs [] check = dict() check dict() dict for i in alphabets:
    segs.append([1 if S[l] == i else 0 for l in range(N)]) i alphabets 1 if S[l] == i else 0 for l in range(N) for l in range(N) l range(N) range N for l in range(N) 1 if S[l] == i else 0 S[l] == i S[l] S l i 1 0 segs.append([1 if S[l] == i else 0 for l in range(N)]) segs.append segs append [1 if S[l] == i else 0 for l in range(N)] for i in range(26):
    segs[i] = SegmentTree(segs[i], 0) i range(26) range 26 segs[i] = SegmentTree(segs[i], 0) segs[i] segs i SegmentTree(segs[i], 0) SegmentTree segs[i] segs i 0 for _ in range(Q):
    Query = list(map(str, input().split()))
    if Query[0] == "1":
        i, c = int(Query[1]), Query[2]
        if check.get(str(i - 1)):
            segs[ord(check[str(i - 1)]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
        else:
            segs[ord(S[i - 1]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
    else:
        l, r = map(int, (Query[1], Query[2]))
        ans = 0
        for i in segs:
            ans += i.query(l - 1, r)
        print(ans) _ range(Q) range Q Query = list(map(str, input().split())) Query list(map(str, input().split())) list map(str, input().split()) map str input().split() ().split () input split if Query[0] == "1":
        i, c = int(Query[1]), Query[2]
        if check.get(str(i - 1)):
            segs[ord(check[str(i - 1)]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
        else:
            segs[ord(S[i - 1]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
    else:
        l, r = map(int, (Query[1], Query[2]))
        ans = 0
        for i in segs:
            ans += i.query(l - 1, r)
        print(ans) Query[0] == "1" Query[0] Query 0 "1" i, c = int(Query[1]), Query[2] i int(Query[1]) int Query[1] Query 1 c Query[2] Query 2 if check.get(str(i - 1)):
            segs[ord(check[str(i - 1)]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
        else:
            segs[ord(S[i - 1]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
     check.get(str(i - 1)) check.get check get str(i - 1) str i - 1 i 1 segs[ord(check[str(i - 1)]) - 97].replace(i - 1, 0) [ord(check[str(i - 1)]) - 97].replace [ord(check[str(i - 1)]) - 97] segs ord(check[str(i - 1)]) - 97 ord(check[str(i - 1)]) ord check[str(i - 1)] check str(i - 1) str i - 1 i 1 97 replace i - 1 i 1 0 segs[ord(c) - 97].replace(i - 1, 1) [ord(c) - 97].replace [ord(c) - 97] segs ord(c) - 97 ord(c) ord c 97 replace i - 1 i 1 1 check[str(i - 1)] = c check[str(i - 1)] check str(i - 1) str i - 1 i 1 c segs[ord(S[i - 1]) - 97].replace(i - 1, 0) [ord(S[i - 1]) - 97].replace [ord(S[i - 1]) - 97] segs ord(S[i - 1]) - 97 ord(S[i - 1]) ord S[i - 1] S i - 1 i 1 97 replace i - 1 i 1 0 segs[ord(c) - 97].replace(i - 1, 1) [ord(c) - 97].replace [ord(c) - 97] segs ord(c) - 97 ord(c) ord c 97 replace i - 1 i 1 1 check[str(i - 1)] = c check[str(i - 1)] check str(i - 1) str i - 1 i 1 c l, r = map(int, (Query[1], Query[2])) l map(int, (Query[1], Query[2])) map int (Query[1], Query[2]) Query[1] Query 1 Query[2] Query 2 r ans = 0 ans 0 for i in segs:
            ans += i.query(l - 1, r)
         i segs ans += i.query(l - 1, r) ans i.query(l - 1, r) i.query i query l - 1 l 1 r print(ans) print ans alphabets = string.ascii_lowercase string.ascii_lowercase alphabets l, r = map(int, (Query[1], Query[2])) map(int, (Query[1], Query[2])) l c = int(Query[1]), Query[2] Query[2] c ans += i.query(l - 1, r) i.query(l - 1, r) ans N = int(input()) int(input()) N class SegmentTree:
    """
    各ノードが半開区間に対応した完全二分木。
    子は親を半分にした区間を持つ。
    構築O(n), 区間に対する操作O(logn), 値の更新O(logn)
    区間に対する操作は最小値, 最大値, 区間に対する和など柔軟に変更して用いよう！
    """

    def __init__(self, x, init_val):  # 構築, init_valは配列の初期値
        self.init_val = init_val
        self.length = 2 ** ((len(x) - 1).bit_length())
        self.data = [init_val] * 2 * self.length
        for i in range(len(x)):
            self.data[i + self.length - 1] = x[i]
        for i in range(self.length - 2, -1, -1):
            self.data[i] = func(self.data[2 * i + 1], self.data[2 * i + 2])

    def teach_current_val(self, index):
        return self.data[index + self.length - 1]

    def replace(self, index, val):  # indexの値をvalに更新
        index += self.length - 1
        self.data[index] = val
        while index:
            index = (index - 1) // 2
            self.data[index] = func(self.data[2 * index + 1], self.data[2 * index + 2])

    def query(self, left, right):  # 半開区間の最小値等を求める, 葉からさかのぼっていくイメージ。
        if right <= left:
            return self.init_val
        left += self.length - 1  # self.dataの位置に合わせる。
        right += self.length - 2  # self.dataの位置に合わせる。半開区間
        ans_ = self.init_val
        while right > left + 1:
            if left & 1 == 0:  # if left_index%2 == 0:
                ans_ = func(ans_, self.data[left])
            if right & 1 == 1:  # if right_index%2 == 1:
                ans_ = func(ans_, self.data[right])
                right -= 1
            left //= 2
            right = (right - 1) // 2
        if left == right:
            ans_ = func(ans_, self.data[left])
        else:
            ans_ = func(func(ans_, self.data[left]), self.data[right])
        return ans_ class SegmentTree:
    """
    各ノードが半開区間に対応した完全二分木。
    子は親を半分にした区間を持つ。
    構築O(n), 区間に対する操作O(logn), 値の更新O(logn)
    区間に対する操作は最小値, 最大値, 区間に対する和など柔軟に変更して用いよう！
    """

    def __init__(self, x, init_val):  # 構築, init_valは配列の初期値
        self.init_val = init_val
        self.length = 2 ** ((len(x) - 1).bit_length())
        self.data = [init_val] * 2 * self.length
        for i in range(len(x)):
            self.data[i + self.length - 1] = x[i]
        for i in range(self.length - 2, -1, -1):
            self.data[i] = func(self.data[2 * i + 1], self.data[2 * i + 2])

    def teach_current_val(self, index):
        return self.data[index + self.length - 1]

    def replace(self, index, val):  # indexの値をvalに更新
        index += self.length - 1
        self.data[index] = val
        while index:
            index = (index - 1) // 2
            self.data[index] = func(self.data[2 * index + 1], self.data[2 * index + 2])

    def query(self, left, right):  # 半開区間の最小値等を求める, 葉からさかのぼっていくイメージ。
        if right <= left:
            return self.init_val
        left += self.length - 1  # self.dataの位置に合わせる。
        right += self.length - 2  # self.dataの位置に合わせる。半開区間
        ans_ = self.init_val
        while right > left + 1:
            if left & 1 == 0:  # if left_index%2 == 0:
                ans_ = func(ans_, self.data[left])
            if right & 1 == 1:  # if right_index%2 == 1:
                ans_ = func(ans_, self.data[right])
                right -= 1
            left //= 2
            right = (right - 1) // 2
        if left == right:
            ans_ = func(ans_, self.data[left])
        else:
            ans_ = func(func(ans_, self.data[left]), self.data[right])
        return ans_ SegmentTree Q = int(input()) int(input()) Q segs = [] [] segs S = input() input() S input = lambda: sys.stdin.readline().strip() lambda: sys.stdin.readline().strip() input check = dict() dict() check r = map(int, (Query[1], Query[2])) map(int, (Query[1], Query[2])) r Query = list(map(str, input().split())) list(map(str, input().split())) Query INF = float('inf') float('inf') INF MOD = 10 ** 9 + 7 10 ** 9 + 7 MOD def func(a, b):
    if a | b == 0:
        return 0
    else:
        return 1 def func(a, b):
    if a | b == 0:
        return 0
    else:
        return 1 func i, c = int(Query[1]), Query[2] int(Query[1]) i ans = 0 0 ans
import sys
import math
import string
import fractions
import random
from operator import itemgetter
import itertools
from collections import deque
import copy
import heapq
import bisect

MOD = 10 ** 9 + 7
INF = float('inf')
input = lambda: sys.stdin.readline().strip()


def func(a, b):
    if a | b == 0:
        return 0
    else:
        return 1


class SegmentTree:
    """
    各ノードが半開区間に対応した完全二分木。
    子は親を半分にした区間を持つ。
    構築O(n), 区間に対する操作O(logn), 値の更新O(logn)
    区間に対する操作は最小値, 最大値, 区間に対する和など柔軟に変更して用いよう！
    """

    def __init__(self, x, init_val):  # 構築, init_valは配列の初期値
        self.init_val = init_val
        self.length = 2 ** ((len(x) - 1).bit_length())
        self.data = [init_val] * 2 * self.length
        for i in range(len(x)):
            self.data[i + self.length - 1] = x[i]
        for i in range(self.length - 2, -1, -1):
            self.data[i] = func(self.data[2 * i + 1], self.data[2 * i + 2])

    def teach_current_val(self, index):
        return self.data[index + self.length - 1]

    def replace(self, index, val):  # indexの値をvalに更新
        index += self.length - 1
        self.data[index] = val
        while index:
            index = (index - 1) // 2
            self.data[index] = func(self.data[2 * index + 1], self.data[2 * index + 2])

    def query(self, left, right):  # 半開区間の最小値等を求める, 葉からさかのぼっていくイメージ。
        if right <= left:
            return self.init_val
        left += self.length - 1  # self.dataの位置に合わせる。
        right += self.length - 2  # self.dataの位置に合わせる。半開区間
        ans_ = self.init_val
        while right > left + 1:
            if left & 1 == 0:  # if left_index%2 == 0:
                ans_ = func(ans_, self.data[left])
            if right & 1 == 1:  # if right_index%2 == 1:
                ans_ = func(ans_, self.data[right])
                right -= 1
            left //= 2
            right = (right - 1) // 2
        if left == right:
            ans_ = func(ans_, self.data[left])
        else:
            ans_ = func(func(ans_, self.data[left]), self.data[right])
        return ans_


N = int(input())
S = input()
Q = int(input())
alphabets = string.ascii_lowercase
segs = []
check = dict()
for i in alphabets:
    segs.append([1 if S[l] == i else 0 for l in range(N)])
for i in range(26):
    segs[i] = SegmentTree(segs[i], 0)
for _ in range(Q):
    Query = list(map(str, input().split()))
    if Query[0] == "1":
        i, c = int(Query[1]), Query[2]
        if check.get(str(i - 1)):
            segs[ord(check[str(i - 1)]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
        else:
            segs[ord(S[i - 1]) - 97].replace(i - 1, 0)
            segs[ord(c) - 97].replace(i - 1, 1)
            check[str(i - 1)] = c
    else:
        l, r = map(int, (Query[1], Query[2]))
        ans = 0
        for i in segs:
            ans += i.query(l - 1, r)
        print(ans)
