#!/usr/bin/env python3
import sys

sys.setrecursionlimit(300000)

class BinaryIndexedTree(object):

    def __init__(self, n):
        # index is 1-based so vals[0] never be used
        self.n = n
        self.vals = [0] * (n + 1)

    def add(self, i, v):
        while i <= self.n:
            self.vals[i] += v
            i += i & -i

    def sum(self, i):
        ret = 0
        while i > 0:
            ret += self.vals[i]
            i -= i & -i
        return ret

    def sum_range(self, l, r):
        # l and r are 1-based index and inclusive
        return self.sum(r) - self.sum(l - 1)


def solve(N, S, Q, queries):
    trees = []
    for i in range(26):
        trees.append(BinaryIndexedTree(N))

    s = []
    for i, c in enumerate(S):
        c_idx = ord(c) - ord('a')
        if 'a' <= c <= 'z':
            trees[c_idx].add(i + 1, 1)
        s.append(c)

    for q in queries:
        if q[0] == '1':
            i, c = int(q[1]), q[2]
            p = s[i - 1]
            s[i - 1] = c
            trees[ord(p) - ord('a')].add(i, -1)
            trees[ord(c) - ord('a')].add(i, 1)
        if q[0] == '2':
            l, r = int(q[1]), int(q[2])
            ret = 0
            for tree in trees:
                cnt = tree.sum_range(l, r)
                if cnt:
                    ret += 1
            print(ret)
        #pprint(get_range_sum(1, 5, bit))
        #print(s)
        #print()

    return

def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))
    S = str(next(tokens))
    Q = int(next(tokens))
    q = []
    for i in range(Q):
        q.append(list(map(str, input().split())))
    solve(N, S, Q, q)

if __name__ == '__main__':
    main() import sys sys sys.setrecursionlimit(300000) sys.setrecursionlimit sys setrecursionlimit 300000 class BinaryIndexedTree(object):

    def __init__(self, n):
        # index is 1-based so vals[0] never be used
        self.n = n
        self.vals = [0] * (n + 1)

    def add(self, i, v):
        while i <= self.n:
            self.vals[i] += v
            i += i & -i

    def sum(self, i):
        ret = 0
        while i > 0:
            ret += self.vals[i]
            i -= i & -i
        return ret

    def sum_range(self, l, r):
        # l and r are 1-based index and inclusive
        return self.sum(r) - self.sum(l - 1) BinaryIndexedTree def __init__(self, n):
        # index is 1-based so vals[0] never be used
        self.n = n
        self.vals = [0] * (n + 1)

     __init__ self.n = n self.n self n n self.vals = [0] * (n + 1) self.vals self vals [0] * (n + 1) [0] 0 n + 1 n 1 self self n n def add(self, i, v):
        while i <= self.n:
            self.vals[i] += v
            i += i & -i

     add while i <= self.n:
            self.vals[i] += v
            i += i & -i

     i <= self.n i self.n self n self.vals[i] += v self.vals[i] self.vals self vals i v i += i & -i i i & -i i -i i self self i i v v def sum(self, i):
        ret = 0
        while i > 0:
            ret += self.vals[i]
            i -= i & -i
        return ret

     sum ret = 0 ret 0 while i > 0:
            ret += self.vals[i]
            i -= i & -i
         i > 0 i 0 ret += self.vals[i] ret self.vals[i] self.vals self vals i i -= i & -i i i & -i i -i i return ret ret self self i i def sum_range(self, l, r):
        # l and r are 1-based index and inclusive
        return self.sum(r) - self.sum(l - 1) sum_range return self.sum(r) - self.sum(l - 1) self.sum(r) - self.sum(l - 1) self.sum(r) self.sum self sum r self.sum(l - 1) self.sum self sum l - 1 l 1 self self l l r r object def solve(N, S, Q, queries):
    trees = []
    for i in range(26):
        trees.append(BinaryIndexedTree(N))

    s = []
    for i, c in enumerate(S):
        c_idx = ord(c) - ord('a')
        if 'a' <= c <= 'z':
            trees[c_idx].add(i + 1, 1)
        s.append(c)

    for q in queries:
        if q[0] == '1':
            i, c = int(q[1]), q[2]
            p = s[i - 1]
            s[i - 1] = c
            trees[ord(p) - ord('a')].add(i, -1)
            trees[ord(c) - ord('a')].add(i, 1)
        if q[0] == '2':
            l, r = int(q[1]), int(q[2])
            ret = 0
            for tree in trees:
                cnt = tree.sum_range(l, r)
                if cnt:
                    ret += 1
            print(ret)
        #pprint(get_range_sum(1, 5, bit))
        #print(s)
        #print()

    return solve trees = [] trees [] for i in range(26):
        trees.append(BinaryIndexedTree(N))

     i range(26) range 26 trees.append(BinaryIndexedTree(N)) trees.append trees append BinaryIndexedTree(N) BinaryIndexedTree N s = [] s [] for i, c in enumerate(S):
        c_idx = ord(c) - ord('a')
        if 'a' <= c <= 'z':
            trees[c_idx].add(i + 1, 1)
        s.append(c)

     i c enumerate(S) enumerate S c_idx = ord(c) - ord('a') c_idx ord(c) - ord('a') ord(c) ord c ord('a') ord 'a' if 'a' <= c <= 'z':
            trees[c_idx].add(i + 1, 1)
         'a' <= c <= 'z' 'a' <= c 'a' c 'z' trees[c_idx].add(i + 1, 1) [c_idx].add [c_idx] trees c_idx add i + 1 i 1 1 s.append(c) s.append s append c for q in queries:
        if q[0] == '1':
            i, c = int(q[1]), q[2]
            p = s[i - 1]
            s[i - 1] = c
            trees[ord(p) - ord('a')].add(i, -1)
            trees[ord(c) - ord('a')].add(i, 1)
        if q[0] == '2':
            l, r = int(q[1]), int(q[2])
            ret = 0
            for tree in trees:
                cnt = tree.sum_range(l, r)
                if cnt:
                    ret += 1
            print(ret)
        #pprint(get_range_sum(1, 5, bit))
        #print(s)
        #print()

     q queries if q[0] == '1':
            i, c = int(q[1]), q[2]
            p = s[i - 1]
            s[i - 1] = c
            trees[ord(p) - ord('a')].add(i, -1)
            trees[ord(c) - ord('a')].add(i, 1)
         q[0] == '1' q[0] q 0 '1' i, c = int(q[1]), q[2] i int(q[1]) int q[1] q 1 c q[2] q 2 p = s[i - 1] p s[i - 1] s i - 1 i 1 s[i - 1] = c s[i - 1] s i - 1 i 1 c trees[ord(p) - ord('a')].add(i, -1) [ord(p) - ord('a')].add [ord(p) - ord('a')] trees ord(p) - ord('a') ord(p) ord p ord('a') ord 'a' add i -1 trees[ord(c) - ord('a')].add(i, 1) [ord(c) - ord('a')].add [ord(c) - ord('a')] trees ord(c) - ord('a') ord(c) ord c ord('a') ord 'a' add i 1 if q[0] == '2':
            l, r = int(q[1]), int(q[2])
            ret = 0
            for tree in trees:
                cnt = tree.sum_range(l, r)
                if cnt:
                    ret += 1
            print(ret)
        #pprint(get_range_sum(1, 5, bit))
        #print(s)
        #print()

     q[0] == '2' q[0] q 0 '2' l, r = int(q[1]), int(q[2]) l int(q[1]) int q[1] q 1 r int(q[2]) int q[2] q 2 ret = 0 ret 0 for tree in trees:
                cnt = tree.sum_range(l, r)
                if cnt:
                    ret += 1
             tree trees cnt = tree.sum_range(l, r) cnt tree.sum_range(l, r) tree.sum_range tree sum_range l r if cnt:
                    ret += 1
             cnt ret += 1 ret 1 print(ret) print ret return N N S S Q Q queries queries def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))
    S = str(next(tokens))
    Q = int(next(tokens))
    q = []
    for i in range(Q):
        q.append(list(map(str, input().split())))
    solve(N, S, Q, q) main def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
     iterate_tokens for line in sys.stdin:
            for word in line.split():
                yield word
     line sys.stdin sys stdin for word in line.split():
                yield word
     word line.split() line.split line split yield word word tokens = iterate_tokens() tokens iterate_tokens() iterate_tokens N = int(next(tokens)) N int(next(tokens)) int next(tokens) next tokens S = str(next(tokens)) S str(next(tokens)) str next(tokens) next tokens Q = int(next(tokens)) Q int(next(tokens)) int next(tokens) next tokens q = [] q [] for i in range(Q):
        q.append(list(map(str, input().split())))
     i range(Q) range Q q.append(list(map(str, input().split()))) q.append q append list(map(str, input().split())) list map(str, input().split()) map str input().split() ().split () input split solve(N, S, Q, q) solve N S Q q if __name__ == '__main__':
    main() __name__ == '__main__' __name__ '__main__' main() main def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))
    S = str(next(tokens))
    Q = int(next(tokens))
    q = []
    for i in range(Q):
        q.append(list(map(str, input().split())))
    solve(N, S, Q, q) def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))
    S = str(next(tokens))
    Q = int(next(tokens))
    q = []
    for i in range(Q):
        q.append(list(map(str, input().split())))
    solve(N, S, Q, q) main class BinaryIndexedTree(object):

    def __init__(self, n):
        # index is 1-based so vals[0] never be used
        self.n = n
        self.vals = [0] * (n + 1)

    def add(self, i, v):
        while i <= self.n:
            self.vals[i] += v
            i += i & -i

    def sum(self, i):
        ret = 0
        while i > 0:
            ret += self.vals[i]
            i -= i & -i
        return ret

    def sum_range(self, l, r):
        # l and r are 1-based index and inclusive
        return self.sum(r) - self.sum(l - 1) class BinaryIndexedTree(object):

    def __init__(self, n):
        # index is 1-based so vals[0] never be used
        self.n = n
        self.vals = [0] * (n + 1)

    def add(self, i, v):
        while i <= self.n:
            self.vals[i] += v
            i += i & -i

    def sum(self, i):
        ret = 0
        while i > 0:
            ret += self.vals[i]
            i -= i & -i
        return ret

    def sum_range(self, l, r):
        # l and r are 1-based index and inclusive
        return self.sum(r) - self.sum(l - 1) BinaryIndexedTree def solve(N, S, Q, queries):
    trees = []
    for i in range(26):
        trees.append(BinaryIndexedTree(N))

    s = []
    for i, c in enumerate(S):
        c_idx = ord(c) - ord('a')
        if 'a' <= c <= 'z':
            trees[c_idx].add(i + 1, 1)
        s.append(c)

    for q in queries:
        if q[0] == '1':
            i, c = int(q[1]), q[2]
            p = s[i - 1]
            s[i - 1] = c
            trees[ord(p) - ord('a')].add(i, -1)
            trees[ord(c) - ord('a')].add(i, 1)
        if q[0] == '2':
            l, r = int(q[1]), int(q[2])
            ret = 0
            for tree in trees:
                cnt = tree.sum_range(l, r)
                if cnt:
                    ret += 1
            print(ret)
        #pprint(get_range_sum(1, 5, bit))
        #print(s)
        #print()

    return def solve(N, S, Q, queries):
    trees = []
    for i in range(26):
        trees.append(BinaryIndexedTree(N))

    s = []
    for i, c in enumerate(S):
        c_idx = ord(c) - ord('a')
        if 'a' <= c <= 'z':
            trees[c_idx].add(i + 1, 1)
        s.append(c)

    for q in queries:
        if q[0] == '1':
            i, c = int(q[1]), q[2]
            p = s[i - 1]
            s[i - 1] = c
            trees[ord(p) - ord('a')].add(i, -1)
            trees[ord(c) - ord('a')].add(i, 1)
        if q[0] == '2':
            l, r = int(q[1]), int(q[2])
            ret = 0
            for tree in trees:
                cnt = tree.sum_range(l, r)
                if cnt:
                    ret += 1
            print(ret)
        #pprint(get_range_sum(1, 5, bit))
        #print(s)
        #print()

    return solve
#!/usr/bin/env python3
import sys

sys.setrecursionlimit(300000)

class BinaryIndexedTree(object):

    def __init__(self, n):
        # index is 1-based so vals[0] never be used
        self.n = n
        self.vals = [0] * (n + 1)

    def add(self, i, v):
        while i <= self.n:
            self.vals[i] += v
            i += i & -i

    def sum(self, i):
        ret = 0
        while i > 0:
            ret += self.vals[i]
            i -= i & -i
        return ret

    def sum_range(self, l, r):
        # l and r are 1-based index and inclusive
        return self.sum(r) - self.sum(l - 1)


def solve(N, S, Q, queries):
    trees = []
    for i in range(26):
        trees.append(BinaryIndexedTree(N))

    s = []
    for i, c in enumerate(S):
        c_idx = ord(c) - ord('a')
        if 'a' <= c <= 'z':
            trees[c_idx].add(i + 1, 1)
        s.append(c)

    for q in queries:
        if q[0] == '1':
            i, c = int(q[1]), q[2]
            p = s[i - 1]
            s[i - 1] = c
            trees[ord(p) - ord('a')].add(i, -1)
            trees[ord(c) - ord('a')].add(i, 1)
        if q[0] == '2':
            l, r = int(q[1]), int(q[2])
            ret = 0
            for tree in trees:
                cnt = tree.sum_range(l, r)
                if cnt:
                    ret += 1
            print(ret)
        #pprint(get_range_sum(1, 5, bit))
        #print(s)
        #print()

    return

def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))
    S = str(next(tokens))
    Q = int(next(tokens))
    q = []
    for i in range(Q):
        q.append(list(map(str, input().split())))
    solve(N, S, Q, q)

if __name__ == '__main__':
    main()
