You are given a string S of length N consisting of lowercase English letters.
Process Q queries of the following two types:
 - Type 1: change the i_q-th character of S to c_q. (Do nothing if the i_q-th character is already c_q.)
 - Type 2: answer the number of different characters occurring in the substring of S between the l_q-th and r_q-th characters (inclusive).

-----Constraints-----
 - N, Q, i_q, l_q, and r_q are integers.
 - S is a string consisting of lowercase English letters.
 - c_q is a lowercase English letter.
 - 1 \leq N \leq 500000
 - 1 \leq Q \leq 20000
 - |S| = N
 - 1 \leq i_q \leq N
 - 1 \leq l_q \leq r_q \leq N
 - There is at least one query of type 2 in each testcase.

-----Input-----
Input is given from Standard Input in the following format:
N
S
Q
Query_1
\vdots
Query_Q

Here, Query_i in the 4-th through (Q+3)-th lines is one of the following:
1 i_q c_q

2 l_q r_q

-----Output-----
For each query of type 2, print a line containing the answer.

-----Sample Input-----
7
abcdbbd
6
2 3 6
1 5 z
2 1 1
1 4 a
1 7 d
2 1 7

-----Sample Output-----
3
1
5

In the first query, cdbb contains three kinds of letters: b , c , and d, so we print 3.
In the second query, S is modified to abcdzbd.
In the third query, a contains one kind of letter: a, so we print 1.
In the fourth query, S is modified to abcazbd.
In the fifth query, S does not change and is still abcazbd.
In the sixth query, abcazbd contains five kinds of letters: a, b, c, d, and z, so we print 5.

```python

USER_FILENAME = "<user_code>"
import sys, json, builtins
import math, heapq, bisect, itertools, functools, collections, statistics, fractions, decimal, operator, array, random, re, string, os, pathlib
try:
    import resource as _res
except Exception:
    _res = None
from collections import Counter, defaultdict, deque, OrderedDict
from functools import lru_cache, reduce
from itertools import accumulate, permutations, combinations, product
from math import gcd, ceil, floor, sqrt
from decimal import Decimal
try:
    from typing import *
except Exception:
    pass
try:
    sys.setrecursionlimit(1_000_000)
except Exception:
    pass
try:
    import site as _site
    try:
        _sys_sites = _site.getsitepackages() if hasattr(_site, "getsitepackages") else []
        for _p in _sys_sites:
            if _p and _p not in sys.path:
                sys.path.append(_p)
    except Exception:
        pass
    try:
        _usp = _site.getusersitepackages()
        if isinstance(_usp, str):
            _usp = [_usp]
        for _p in _usp:
            if _p and _p not in sys.path:
                sys.path.append(_p)
    except Exception:
        pass
except Exception:
    pass

ns = {"__name__": "__main__"}
for _k, _v in list(globals().items()):
    if not _k.startswith("_"):
        ns[_k] = _v
_CODE = 'class SegmentTree():\n    """A segment Tree.\n\n    This is a segment tree without recursions.\n    This can support queries as follows:\n     - update a single value in O(logN).\n     - get the folded value of values in a segment [l, r) in O(logN)\n    N is the length of the given iterable value.\n\n    Parameters\n    ----------\n    iterable : Iterable[_T]\n        An iterable value which will be converted into a segment tree\n    func : Callable[[_T, _T], _T]\n        A binary function which returns the same type as given two.\n        This has to satisfy the associative law:\n            func(a, func(b, c)) = func(func(a, b), c)\n    e : _T\n        The identity element of the given func.\n        In other words, this satisfies:\n            func(x, e) = func(e, x) = x\n    """\n    \n    def __init__(self, iterable, func, e):\n        self.func = func\n        self.e = e\n\n        ls = list(iterable)\n        self.n = 1 << len(ls).bit_length()\n        ls.extend( [self.e] * (self.n - len(ls)) )\n\n        self.data = [self.e] * self.n + ls\n        for i in range(self.n-1, 0, -1):\n            self.data[i] = self.func(self.data[2*i], self.data[2*i+1])\n\n    def replace(self, index, value):\n        """replace the old value of the given index with the given new value.\n\n        This replaces the old value of the given index with the given new value in O(logN).\n        This is like "list[index] = value".\n\n        Parameters\n        ----------\n        index : int\n            The index of the value which will be replaced.\n        value : _T\n            The new value with which the old value will be replaced.\n        """\n        index += self.n\n        self.data[index] = value\n        index //= 2\n        while index > 0:\n            self.data[index] = self.func(self.data[2*index], self.data[2*index+1])\n            index //= 2\n        \n    def folded(self, l, r):\n        """get the folded value of values in a segment [l, r).\n\n        This get the folded value of values in a segment [l, r) in O(logN).\n        If func is add, it returns the sum of values in [l, r).\n        In other words, this is eqivalent to "sum(list[l:r])".\n        If func is other functions, then this is equivalent to "accumulate(list[l:r], func)".\n\n        Parameters\n        ----------\n        l : int\n            The left edge.\n        r : int\n            The right edge.\n\n        Returns\n        -------\n        _T(the same type as the type of the element of the given iterable)\n            This is equivalent to func(list[l], func(list[l+1], ... ) ).\n            If func is represented as \'*\', then it\'s:\n            list[l] * list[l+1] * ... * list[r-1] \n        """\n\n        left_folded = self.e\n        right_folded = self.e\n        l += self.n\n        r += self.n\n        while l < r:\n            if l % 2:\n                left_folded = self.func(left_folded, self.data[l])\n                l += 1\n            if r % 2:\n                r -= 1\n                right_folded = self.func(self.data[r], right_folded)\n            l //= 2\n            r //= 2\n        \n        return self.func(left_folded, right_folded)\n\n\nfrom operator import or_\n\nN = int(input())\nS = input()\n\nls = [1 << (ord(c) - ord(\'a\')) for c in S]\nsegtree = SegmentTree(ls, or_, 0)\n\nQ = int(input())\nfor _ in range(Q):\n    s = input()\n    if s[0] == \'1\':\n        i, c = s[2:].split()\n        segtree.replace(int(i)-1, 1 << (ord(c) - ord(\'a\')))\n    else:\n        l, r = list(map(int, s[2:].split()))\n        value = segtree.folded(l-1, r)\n        print((format(value, \'b\').count(\'1\')))\n'
_co = compile(_CODE, USER_FILENAME, "exec")
exec(_co, ns, ns)

```

Measured memory_bytes: 17195