Problem:
 Score : 500 points    Problem Statement 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 1 7
abcdbbd
6
2 3 6
1 5 z
2 1 1
1 4 a
1 7 d
2 1 7      Sample Output 1 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 .

Solution (Python):
from typing import List, Any


def read_int() -> int:
    return int(input().strip())


def read_ints() -> List[int]:
    return list(map(int, input().strip().split(' ')))


class SegmentTree:
    
    def __init__(self, array):
        self.n = len(array)
        self.array = [0 for _ in array]+array
        for i in range(self.n-1, 0, -1):
            self.array[i] = self.array[i<<1]|self.array[i<<1|1]

    def set(self, i, v):
        p = self.n+i
        self.array[p] = v
        while p > 1:
            p >>= 1
            self.array[p] = self.array[p<<1]|self.array[p<<1|1]

    def count(self, l, r):
        l += self.n
        r += self.n
        answer = 0
        while l < r:
            if l&1:
                answer |= self.array[l]
                l += 1
            if r&1:
                r -= 1
                answer |= self.array[r]
            l >>= 1
            r >>= 1
        return answer


def bit_count(a):
    answer = 0
    while a:
        answer += a&1
        a >>= 1
    return answer


def solve():
    ALPHABETS = 'abcdefghijklmnopqrstuvwxyz'
    N = read_int()
    S = input()
    Q = read_int()
    segment_tree = SegmentTree([1<<(ALPHABETS.index(c)) for c in S])
    for _ in range(Q):
        cmd = input().strip().split(' ')
        if cmd[0] == '1':
            n = 1<<(ALPHABETS.index(cmd[2]))
            segment_tree.set(int(cmd[1])-1, n)
        else:
            l, r = int(cmd[1])-1, int(cmd[2])
            print(bit_count(segment_tree.count(l, r)))


if __name__ == '__main__':
    solve()

Solution (Python):
class segtree:

    def __init__(self, n, identity):
        
        nb = bin(n)[2:]
        bc = sum([int(digit) for digit in nb])
        if bc == 1:
            self.num_end_leaves = 2 ** (len(nb) - 1)
        else:
            self.num_end_leaves = 2 ** (len(nb))

        self.array = [identity for i in range(self.num_end_leaves * 2)]
        self.identity = identity

    def update(self, x, val):
        actual_x = x + self.num_end_leaves
        self.array[actual_x] = val
        while actual_x > 0:
            actual_x = actual_x // 2
            self.array[actual_x] = self.array[actual_x * 2] | self.array[actual_x * 2 + 1]

    def get(self, q_left, q_right, arr_ind=1, leaf_left=0, depth=0):
        width_of_floor = self.num_end_leaves // (2 ** depth)
        leaf_right = leaf_left + width_of_floor - 1

        if leaf_left > q_right or leaf_right < q_left:
            return self.identity

        elif leaf_left >= q_left and leaf_right <= q_right:
            return self.array[arr_ind]

        else:
            val_l = self.get(q_left, q_right, 2 * arr_ind, leaf_left, depth + 1)
            val_r = self.get(q_left, q_right, 2 * arr_ind + 1, leaf_left + width_of_floor // 2, depth + 1)
            return val_l | val_r

N = int(input())
S = list(input())
Q = int(input())
T = {}
j = 1
for i in range(97, 97+26):
    T[chr(i)] = j
    j *= 2

s_tree = segtree(N+1, 0)

for i in range(N):
    s_tree.update(i+1, T[S[i]])

for i in range(Q):
    A = list(input().split())
    a, b, c = A
    if a == "2":
        K = bin(s_tree.get(int(b), int(c)))[2:]
        d = 0
        for i in K:
            if i == "1":
                d += 1
        print(d)
    else:
        s_tree.update(int(b), T[c])

Solution (Python):

class BIT:
    """Binary Indexed Tree (Fenwick Tree)
    Range Sum QueryにO(log N)時間で答える
    1-indexed
    """
    def __init__(self, n):
        self.size = n
        self.tree = [0] * (n + 1)
        self.depth = n.bit_length()
 
    def sum(self, i):
        """a[1]~a[i]の区間和を取得"""
        s = 0
        while i > 0:
            s += self.tree[i]
            i -= i & -i
        return s
 
    def add(self, i, x):
        """a[i]にxを足す"""
        while i <= self.size:
            self.tree[i] += x
            i += i & -i

    def lower_bound(self, x):
        """ 累積和がx以上になる最小のindexと、その直前までの累積和 """
        sum_ = 0
        pos = 0
        for i in range(self.depth, -1, -1):
            k = pos + (1 << i)
            if k <= self.size and sum_ + self.tree[k] < x:
                sum_ += self.tree[k]
                pos += 1 << i
        return pos + 1, sum_
 
def main():
    N = int(input())
    S = list(input())
    Q = int(input())
    alphabets = list("abcdefghijklmnopqrstuvwxyz")
    c2n = {c: i for i, c in enumerate(alphabets)}
    
    Trees = [BIT(N+2) for _ in range(26)]

    for i in range(N):
        Trees[c2n[S[i]]].add(i+1, 1)
    
    for _ in range(Q):
        tmp = list(input().split())
        if tmp[0] == "1":
            _, i, c = tmp
            i = int(i)
            Trees[c2n[S[i-1]]].add(i, -1)
            Trees[c2n[c]].add(i, 1)
            S[i-1] = c
        else:
            ans = 0
            _, l, r = tmp
            l = int(l)
            r = int(r)
            for char in range(26):
                if Trees[char].sum(r) - Trees[char].sum(l-1) > 0:
                    ans += 1
            print(ans)

if __name__ == "__main__":
    main()

Solution (Python):
class BalancingTree:
    """平衡二分木のクラス
    Pivotを使った実装.
    0以上2^n - 2以下の整数を扱う
    """
    def __init__(self, n):
        """
        2の指数nで初期化
        """
        self.N = n
        self.root = self.node(1<<n, 1<<n)

    def debug(self):
        """デバッグ用の関数"""
        def debug_info(nd_):
            return (nd_.value - 1, nd_.pivot - 1, nd_.left.value - 1 if nd_.left else -1, nd_.right.value - 1 if nd_.right else -1)

        def debug_node(nd):
            re = []
            if nd.left:
                re += debug_node(nd.left)
            if nd.value: re.append(debug_info(nd))
            if nd.right:
                re += debug_node(nd.right)
            return re
        print("Debug - root =", self.root.value - 1, debug_node(self.root)[:50])

    def append(self, v):
        """
        v を追加（その時点で v はない前提）
        """
        v += 1
        nd = self.root
        while True:
            if v == nd.value:
                
                return 0
            else:
                mi, ma = min(v, nd.value), max(v, nd.value)
                if mi < nd.pivot:
                    nd.value = ma
                    if nd.left:
                        nd = nd.left
                        v = mi
                    else:
                        p = nd.pivot
                        nd.left = self.node(mi, p - (p&-p)//2)
                        break
                else:
                    nd.value = mi
                    if nd.right:
                        nd = nd.right
                        v = ma
                    else:
                        p = nd.pivot
                        nd.right = self.node(ma, p + (p&-p)//2)
                        break

    def leftmost(self, nd):
        if nd.left: return self.leftmost(nd.left)
        return nd

    def rightmost(self, nd):
        if nd.right: return self.rightmost(nd.right)
        return nd

    def find_l(self, v):
        """
        vより真に小さいやつの中での最大値（なければ-1）
        """
        v += 1
        nd = self.root
        prev = 0
        if nd.value < v: prev = nd.value
        while True:
            if v <= nd.value:
                if nd.left:
                    nd = nd.left
                else:
                    return prev - 1
            else:
                prev = nd.value
                if nd.right:
                    nd = nd.right
                else:
                    return prev - 1

    def find_r(self, v):
        """
        vより真に大きいやつの中での最小値（なければRoot）
        """
        v += 1
        nd = self.root
        prev = 0
        if nd.value > v: prev = nd.value
        while True:
            if v < nd.value:
                prev = nd.value
                if nd.left:
                    nd = nd.left
                else:
                    return prev - 1
            else:
                if nd.right:
                    nd = nd.right
                else:
                    return prev - 1

    @property
    def max(self):
        """最大値の属性"""
        return self.find_l((1<<self.N)-1)

    @property
    def min(self):
        """最小値の属性"""
        return self.find_r(-1)

    def delete(self, v, nd = None, prev = None):
        """
        値がvのノードがあれば削除（なければ何もしない）
        """
        v += 1
        if not nd: nd = self.root
        if not prev: prev = nd
        while v != nd.value:
            prev = nd
            if v <= nd.value:
                if nd.left:
                    nd = nd.left
                else:
                    return
            else:
                if nd.right:
                    nd = nd.right
                else:
                    return
        if (not nd.left) and (not nd.right):
            if nd.value < prev.value:
                prev.left = None
            else:
                prev.right = None
        elif not nd.left:
            if nd.value < prev.value:
                prev.left = nd.right
            else:
                prev.right = nd.right
        elif not nd.right:
            if nd.value < prev.value:
                prev.left = nd.left
            else:
                prev.right = nd.left
        else:
            nd.value = self.leftmost(nd.right).value
            self.delete(nd.value - 1, nd.right, nd)

    def __contains__(self, v: int) -> bool:
        return self.find_r(v - 1) == v

    class node:
        """ノードをあらわすクラス
        v: 値
        p: ピボット値
        で初期化
        """
        def __init__(self, v, p):
            self.value = v
            self.pivot = p
            self.left = None
            self.right = None

Trees = [BalancingTree(50) for _ in range(26)]
N = int(input())
S = input()
Q = int(input())
alphabets = list("abcdefghijklmnopqrstuvwxyz")
c2n = {c: i for i, c in enumerate(alphabets)}
for i in range(N):
    Trees[c2n[S[i]]].append(i+1)
S = list(S)
for _ in range(Q):
    tmp = list(input().split())
    if tmp[0] == "1":
        _, i, c = tmp
        i = int(i)
        bef = S[i-1]
        if bef == c:
            continue
        Trees[c2n[bef]].delete(i)
        Trees[c2n[c]].append(i)
        S[i-1] = c
    else:
        _, l, r = tmp
        l = int(l)
        r = int(r)
        ans = 0
        for char in range(26):
            res = Trees[char].find_r(l-1)
            if l <= res <= r:
                ans += 1
        print(ans)

Solution (Python):




from __future__ import division, print_function
from fractions import Fraction
import sys
import os
from io import BytesIO, IOBase
from itertools import *
import bisect
from heapq import *
from math import *
from copy import *
from collections import deque
from collections import Counter as counter  
from itertools import combinations as comb  
from itertools import permutations as permutate
from bisect import bisect_left as bl



from bisect import bisect_right as br
from bisect import bisect







BUFSIZE = 8192
from sys import stderr


class FastIO(IOBase):
    newlines = 0

    def __init__(self, file):
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = "x" in file.mode or "r" not in file.mode
        self.write = self.buffer.write if self.writable else None

    def read(self):
        while True:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines = 0
        return self.buffer.read()

    def readline(self):
        while self.newlines == 0:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b"\n") + (not b)
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines -= 1
        return self.buffer.readline()

    def flush(self):
        if self.writable:
            os.write(self._fd, self.buffer.getvalue())
            self.buffer.truncate(0), self.buffer.seek(0)


class IOWrapper(IOBase):
    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode("ascii"))
        self.read = lambda: self.buffer.read().decode("ascii")
        self.readline = lambda: self.buffer.readline().decode("ascii")


def print(*args, **kwargs):
    """Prints the values to a stream, or to sys.stdout by default."""
    sep, file = kwargs.pop("sep", " "), kwargs.pop("file", sys.stdout)
    at_start = True
    for x in args:
        if not at_start:
            file.write(sep)
        file.write(str(x))
        at_start = False
    file.write(kwargs.pop("end", "\n"))
    if kwargs.pop("flush", False):
        file.flush()


if sys.version_info[0] < 3:
    sys.stdin, sys.stdout = FastIO(sys.stdin), FastIO(sys.stdout)
else:
    sys.stdin, sys.stdout = IOWrapper(sys.stdin), IOWrapper(sys.stdout)





from types import GeneratorType


def iterative(f, stack=[]):
    def wrapped_func(*args, **kwargs):
        if stack: return f(*args, **kwargs)
        to = f(*args, **kwargs)
        while True:
            if type(to) is GeneratorType:
                stack.append(to)
                to = next(to)
                continue
            stack.pop()
            if not stack: break
            to = stack[-1].send(to)
        return to

    return wrapped_func







mod = 1000000007


def inp(): return sys.stdin.readline().rstrip("\r\n")  


def out(var): sys.stdout.write(str(var))  


def lis(): return list(map(int, inp().split()))


def stringlis(): return list(map(str, inp().split()))


def sep(): return map(int, inp().split())


def strsep(): return map(str, inp().split())


def zerolist(n): return [0] * n


def nextline(): out("\n")  


def testcase(t):
    for p in range(t):
        solve()


def printlist(a):
    for p in range(0, len(a)):
        out(str(a[p]) + ' ')

def pow(x, y, p):
    res = 1  
    x = x % p  
    if (x == 0):
        return 0
    while (y > 0):
        if ((y & 1) == 1):  
            res = (res * x) % p

        y = y >> 1  
        x = (x * x) % p
    return res

from functools import reduce

def factors(n):
    return set(reduce(list.__add__,
                ([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))

def gcd(a, b):
    if a == b: return a
    while b > 0: a, b = b, a % b
    return a


from operator import add
def solve():
    def sep():
        return map(int, input().strip().split(" "))

    def lis():
        return list(map(int, input().strip().split(" ")))
    class SegmentTree:
        def __init__(self, data, default=0, func=add):
            """initialize the segment tree with data"""
            self._default = default
            self._func = func
            self._len = len(data)
            self._size = _size = 1 << (self._len - 1).bit_length()

            self.data = [default] * (_size) + data + [default] * (_size - self._len)
            for i in range(_size - 1, -1, -1):
                self.data[i] = func(self.data[2 * i], self.data[2 * i + 1])

        def __delitem__(self, idx):
            self[idx] = self._default

        def __getitem__(self, idx):
            return self.data[idx + self._size]

        def __setitem__(self, idx, value):
            idx += self._size
            self.data[idx] = value
            idx >>= 1
            while idx:
                self.data[idx] = self._func(self.data[2 * idx], self.data[2 * idx + 1])
                idx >>= 1


        def __len__(self):
            return self._len



        def query(self, start, stop):
            """func  of data[start, stop)"""
            start += self._size
            stop +=  self._size

            res_left = res_right = self._default
            while start < stop:
                if start & 1:
                    res_left = self._func(res_left, self.data[start])
                    start += 1
                if stop & 1:
                    stop -= 1
                    res_right = self._func(self.data[stop], res_right)
                start >>= 1
                stop >>= 1

            return self._func(res_left, res_right)


    def fun(i1,i2):
        s1=i1
        s2=i2
        k=s1.union(s2)
        return(k)

    n=int(input())
    ar=inp()
    temp=[]
    for i in range(n):
        t=set().copy()
        t.add(ar[i])
        temp.append(t)
    defa=(set().copy())
    seg=SegmentTree(temp,default=defa,func=fun)
    m=int(inp())
    for _ in range(m):
        
        a,b,c=(i for i in inp().strip().split(" "))
        if a=="2":
            b=int(b)
            c=int(c)
            print(len(seg.query(b-1,c)))
        else:
            b=int(b)
            t=set().copy()
            t.add(c)
            seg[b-1]=t.copy()













solve()

Solution (Python):
class SegmentTree:
    def __init__(self,n,ele=0):
        self.ide_ele = ele
        self.num =2**(n-1).bit_length()
        self.seg=[self.ide_ele]*2*self.num

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

    def init(self,init_val):
        for i in range(len(init_val)):
            self.seg[i+self.num-1]=init_val[i]
        for i in range(self.num-2,-1,-1) :
            self.seg[i]=self.segfunc(self.seg[2*i+1],self.seg[2*i+2]) 

    def update(self,k,x):
        k += self.num-1
        if self.seg[k]==x:
          return 0
        self.seg[k] = x
        while k:
            k = (k-1)//2
            self.seg[k] = self.segfunc(self.seg[k*2+1],self.seg[k*2+2])

    def query(self,p,q):
        if q<=p:
            return self.ide_ele
        p += self.num-1
        q += self.num-2
        res=self.ide_ele
        while q-p>1:
            if p&1 == 0:
                res = self.segfunc(res,self.seg[p])
            if q&1 == 1:
                res = self.segfunc(res,self.seg[q])
                q -= 1
            p = p//2
            q = (q-1)//2
        if p == q:
            res = self.segfunc(res,self.seg[p])
        else:
            res = self.segfunc(self.segfunc(res,self.seg[p]),self.seg[q])
        return res
      
N,S,Q=int(input()),input(),int(input())
d={'a': 1, 'b': 2, 'c': 4, 'd': 8, 'e': 16, 'f': 32, 'g': 64, 'h': 128, 'i': 256, 'j': 512, 'k': 1024, 'l': 2048, 'm': 4096, 'n': 8192, 'o': 16384, 'p': 32768, 'q': 65536, 'r': 131072, 's': 262144, 't': 524288, 'u': 1048576, 'v': 2097152, 'w': 4194304, 'x': 8388608, 'y': 16777216, 'z': 33554432}

initial=[d[c] for c in list(S)]

ST=SegmentTree(N)
ST.init(initial)

for _ in range(Q):
    typ,a,b=input().split()
    if typ=='1':
        i,c=int(a),d[b]
        ST.update(i-1,c)
    else:
        l,r=int(a)-1,int(b)
        x=bin(ST.query(l,r))[2:]
        print(sum(map(int,list(x))))

Solution (Python):

n=int(input())
s=input()
q=int(input())


Seg_Len=1<<19
seg=[0 for i in range(Seg_Len*2)]

def add(ind,v):
    ind+=Seg_Len-1 
    seg[ind]=v  
    while(1):
        ind//=2
        if(ind==0):
            break  
        seg[ind]=seg[ind*2]|seg[ind*2+1]
        
def sum1(l,r):
    l+=Seg_Len-1
    r+=Seg_Len-1
    ans=0
    while(l<r):
        if(l%2==1):
            ans|=seg[l]
            l+=1
        l//=2
        if(r%2==1):
            ans|=seg[r-1]
            r-=1
        r//=2
    tmp=0
    while(ans):
        if(ans & 1):
            tmp+=1
        ans>>=1
    return tmp

alp='abcdefghijklmnopqrstuvwxyz'
d={}
for i in range(len(alp)):
    d[alp[i]]=2**i
    
for i in range(len(s)):
    add((i+1),d[s[i]])
for i in range(q):
    com,a,b=input().split()
    if(com=='1'):
        ind=int(a)
        v=d[b]
        add(ind,v)
    if(com=='2'):
        l=int(a)
        r=int(b)
        
        print(sum1(l,r+1))

Solution (Python):
n = int(input())
s = list(input())
s = [ord(i)-97 for i in s]

dic = {}
for i in range(26):
    dic[i] = []

for i in range(n):
    dic[s[i]].append(i)

for i in range(26):
    dic[i].append(float('inf'))

from bisect import bisect_left
q = int(input())
for i in range(q):
    x, y, z = input().split()
    if x == '1':
        y, z = int(y) - 1, ord(z) - 97
        p = bisect_left(dic[s[y]], y)
        dic[s[y]].pop(p)
        dic[z].insert(bisect_left(dic[z], y), y)
        s[y] = z
    else:
        res = 0
        y, z = int(y) - 1, int(z) - 1
        for i in range(26):
            p = dic[i][bisect_left(dic[i], y)]
            if p <= z:
                res += 1
        print(res)

Solution (Python):
n = int(input())
s = list(input())

dic = {}
for i in range(26):
    dic[chr(i+97)] = []

for i in range(n):
    dic[s[i]].append(i)

for i in range(26):
    dic[chr(i+97)].append(float('inf'))

from bisect import bisect_left
q = int(input())
for i in range(q):
    x, y, z = input().split()
    if x == '1':
        y = int(y) - 1
        p = bisect_left(dic[s[y]], y)
        dic[s[y]].pop(p)
        dic[z].insert(bisect_left(dic[z], y), y)
        s[y] = z
    else:
        res = 0
        y, z = int(y) - 1, int(z) - 1
        for i in range(26):
            p = dic[chr(i+97)][bisect_left(dic[chr(i+97)], y)]
            if p <= z:
                res += 1
        print(res)

Solution (Python):
import sys
import itertools

import time
import math
from heapq import heappop, heappush
from collections import defaultdict
from collections import Counter
from collections import deque
from itertools import permutations
sys.setrecursionlimit(10 ** 7)
 
INF = 10 ** 18
MOD = 10 ** 9 + 7
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines


N = int(input())
S = list(input())
Q = int(input())
q_list = [list(input().split()) for _ in range(Q)]

bit_tree = [[0] * (N+1) for _ in range(26)]
def BIT_add(i, tree):
    while i <= N:
        tree[i] += 1
        i += i&(-i)

def BIT_sub(i, tree):
    while i <= N:
        tree[i] -= 1
        i += i&(-i)

def BIT_sum(i, tree):
    s = 0
    while i:
        s += tree[i]
        i -= i&(-i)
    return s

for i in range(N):
    x = ord(S[i]) - ord('a')
    BIT_add(i + 1, bit_tree[x])

for q in range(Q):
    line = q_list[q]
    if line[0] == '1':
        i, c = line[1:]
        i = int(i) - 1
        old_c = ord(S[i]) - ord('a')
        new_c = ord(c) - ord('a')
        BIT_sub(i + 1, bit_tree[old_c])
        BIT_add(i + 1, bit_tree[new_c])
        S[i] = c
    else:
        l, r = map(int, line[1:])
        now = 0
        for i in range(26):
            cnt = BIT_sum(r, bit_tree[i]) - BIT_sum(l - 1, bit_tree[i])
            if cnt > 0:
                now += 1
        print(now)

Solution (Python):
import sys
input = sys.stdin.readline

def I(): return int(input())
def MI(): return map(int, input().split())
def LI(): return list(map(int, input().split()))

def main():
    class Segtree:
        def __init__(self, A, ide_ele, initialize = True, segf = max):
            self.N = len(A)
            self.N0 = 2**(self.N-1).bit_length()
            self.ide_ele = ide_ele
            self.segf = segf
            if initialize:
                self.data = [ide_ele]*self.N0 + A + [ide_ele]*(self.N0 - self.N)
                for i in range(self.N0-1, 0, -1):
                    self.data[i] = self.segf(self.data[2*i], self.data[2*i+1]) 
            else:
                self.data = [ide_ele]*(2*self.N0)

        def update(self, k, x):
            k += self.N0
            self.data[k] = x
            while k > 0 :
                k = k >> 1
                self.data[k] = self.segf(self.data[2*k], self.data[2*k+1])

        def query(self, l, r):
            L, R = l+self.N0, r+self.N0
            s = self.ide_ele
            t = self.ide_ele
            while L < R:
                if R & 1:
                    R -= 1
                    t = self.segf(self.data[R],t)
                if L & 1:
                    s = self.segf(s,self.data[L])
                    L += 1
                L >>= 1
                R >>= 1
            return self.segf(s,t)

        
        
        
        def binsearch(self, l, r, check, reverse = False):
            L, R = l+self.N0, r+self.N0
            SL, SR = [], []
            while L < R:
                if R & 1:
                    R -= 1
                    SR.append(R)
                if L & 1:
                    SL.append(L)
                    L += 1
                L >>= 1
                R >>= 1

            if reverse:
                pre = self.ide_ele
                for idx in (SR + SL[::-1]):
                    if check(self.segf(self.data[idx], pre)):
                        break
                    else:
                        pre = self.segf(self.data[idx], pre)
                else:
                    return None
                while idx < self.N0:
                    if check(self.segf(self.data[2*idx+1], pre)):
                        idx = 2*idx + 1
                    else:
                        pre = self.segf(self.data[2*idx+1], pre)
                        idx = 2*idx
                return idx - self.N0
            else:
                pre = self.ide_ele
                for idx in (SL + SR[::-1]):
                    if not check(self.segf(pre, self.data[idx])):
                        pre = self.segf(pre, self.data[idx])
                    else:
                        break
                else:
                    return None
                while idx < self.N0:
                    if check(self.segf(pre, self.data[2*idx])):
                        idx = 2*idx
                    else:
                        pre = self.segf(pre, self.data[2*idx])
                        idx = 2*idx + 1
                return idx - self.N0
    

    N=I()
    S=input()
    Q=I()
    
    A=[]
    for i in range(N):
        ii=ord(S[i])
        aaa=set([ii])
        A.append(aaa)
    
    seg=Segtree(A,set([]),segf=lambda a,b:a|b)
    
    for _ in range(Q):
        q=input().split()
        if q[0]=="1":
            i=int(q[1])-1
            c=q[2]
            seg.update(i,set([ord(c)]))
        else:
            l=int(q[1])
            r=int(q[2])
            ans=seg.query(l-1,r)
            print(len(ans))
    

main()

Solution (Python):
import sys
input = sys.stdin.readline

def I(): return int(input())
def MI(): return map(int, input().split())
def LI(): return list(map(int, input().split()))

def main():
    class Segtree:
        def __init__(self, A, ide_ele, initialize = True, segf = max):
            self.N = len(A)
            self.N0 = 2**(self.N-1).bit_length()
            self.ide_ele = ide_ele
            self.segf = segf
            if initialize:
                self.data = [ide_ele]*self.N0 + A + [ide_ele]*(self.N0 - self.N)
                for i in range(self.N0-1, 0, -1):
                    self.data[i] = self.segf(self.data[2*i], self.data[2*i+1]) 
            else:
                self.data = [ide_ele]*(2*self.N0)

        def update(self, k, x):
            k += self.N0
            self.data[k] = x
            while k > 0 :
                k = k >> 1
                self.data[k] = self.segf(self.data[2*k], self.data[2*k+1])

        def query(self, l, r):
            L, R = l+self.N0, r+self.N0
            s = self.ide_ele
            t = self.ide_ele
            while L < R:
                if R & 1:
                    R -= 1
                    t = self.segf(self.data[R],t)
                if L & 1:
                    s = self.segf(s,self.data[L])
                    L += 1
                L >>= 1
                R >>= 1
            return self.segf(s,t)

        
        
        
        def binsearch(self, l, r, check, reverse = False):
            L, R = l+self.N0, r+self.N0
            SL, SR = [], []
            while L < R:
                if R & 1:
                    R -= 1
                    SR.append(R)
                if L & 1:
                    SL.append(L)
                    L += 1
                L >>= 1
                R >>= 1

            if reverse:
                pre = self.ide_ele
                for idx in (SR + SL[::-1]):
                    if check(self.segf(self.data[idx], pre)):
                        break
                    else:
                        pre = self.segf(self.data[idx], pre)
                else:
                    return None
                while idx < self.N0:
                    if check(self.segf(self.data[2*idx+1], pre)):
                        idx = 2*idx + 1
                    else:
                        pre = self.segf(self.data[2*idx+1], pre)
                        idx = 2*idx
                return idx - self.N0
            else:
                pre = self.ide_ele
                for idx in (SL + SR[::-1]):
                    if not check(self.segf(pre, self.data[idx])):
                        pre = self.segf(pre, self.data[idx])
                    else:
                        break
                else:
                    return None
                while idx < self.N0:
                    if check(self.segf(pre, self.data[2*idx])):
                        idx = 2*idx
                    else:
                        pre = self.segf(pre, self.data[2*idx])
                        idx = 2*idx + 1
                return idx - self.N0
    

    N=I()
    S=input()
    Q=I()
    
    A=[]
    for i in range(N):
        aaa=set(S[i])
        A.append(aaa)
    
    seg=Segtree(A,set([]),segf=lambda a,b:a|b)
    
    for _ in range(Q):
        q=input().split()
        if q[0]=="1":
            i=int(q[1])-1
            c=q[2]
            seg.update(i,set([c]))
        else:
            l=int(q[1])
            r=int(q[2])
            ans=seg.query(l-1,r)
            print(len(ans))
    

main()