Buggy python submission (verdict: Runtime Error):
import bisect

def sRaw():
    return input().rstrip("\r")


def iRaw():
    return int(input())


def ssRaw():
    return input().split()


def isRaw():
    return list(map(int, ssRaw()))


INF = 1 << 29

DIV = (10**9) + 7


def mod_inv_prime(a, mod=DIV):
    return pow(a, mod-2, mod)


def ncr(n, r, mod=DIV):
	r = min(r, n-r)
	ret = 1
	for i in range(1, r+1):
		ret = ret * (n-i+1) % mod
		ret = ret * mod_inv(i, mod) % mod
	return ret


def mod_inv(a, b):
    r = a
    w = b
    u = 1
    v = 0
    while w != 0:
        t = r//w
        r -= t*w
        r, w = w, r
        u -= t*v
        u, v = v, u
    return (u % b+b) % b


def CONV_TBL(max, mod=DIV):
    fac, finv, inv = [0]*max, [0]*max, [0]*max
    fac[0] = fac[1] = 1
    finv[0] = finv[1] = 1
    inv[1] = 1
    for i in range(2, max):
        fac[i] = fac[i-1]*i % mod
        inv[i] = mod - inv[mod % i] * (mod//i) % mod
        finv[i] = finv[i-1]*inv[i] % mod

    class CONV:
        def __init__(self):
            pass

        def ncr(self, n, k):
            if(n < k):
                return 0
            if(n < 0 or k < 0):
                return 0
            return fac[n]*(finv[k]*finv[n-k] % mod) % mod
    return CONV()


def main():
    N = iRaw()
    S = sRaw()
    Q = iRaw()
    Qs = [c for c in S]
    c_dict={}
    for c in range(ord('a'), ord('z')+1):
        c_dict[chr(c)] = []
    for idx,c in enumerate(Qs):
        c_dict[c].append(idx)
        
    for qidx in range(Q):
        query = ssRaw()
        if query[0]=="1":
            i = int(query[1])-1
            c = query[2]
            old_c = Qs[i]
            if c!= old_c:
                Qs[i]=c
                bi = bisect.bisect_left(c_dict[old_c],i)
                tmp = c_dict[S[i]]  # S[i]を更新しなきゃ
                del c_dict[S[i]][bisect.bisect_left(tmp, i)]
                # cのidxに挿入し直す
                bisect.insort_left(c_dict[c], bi)
        else:
            l = int(query[1])-1
            r = int(query[2])-1
            ret = 0
            for v in c_dict.values():
                l_idx = bisect.bisect_left(v, l)
                r_idx = bisect.bisect_right(v, r)
                if r_idx - l_idx > 0:
                    ret += 1
            print(ret)

    return -1


if __name__ == "__main__":
    main()


Fixed submission:
import bisect
import math
from collections import deque

def sRaw():
    return input().rstrip("\r")


def iRaw():
    return int(input())


def ssRaw():
    return input().split()


def isRaw():
    return list(map(int, ssRaw()))


INF = 1 << 29


class Node:
    def __init__(self, val, idx=0):
        self.val = val
        self.idx = idx

    def __str__(self):
        return 'val : ' + str(self.val) + ' idx : ' + str(self.idx)

# 0-idxed SegmentTree
class SegmentTree:
    def __init__(self, N, vals, default_value=INF):
        self.N0 = pow(2, (N-1).bit_length())
        self.nodes = [Node(default_value, i+1-self.N0)
                      for i in range(2*self.N0-1)]
        for i in reversed(range(2*self.N0-1)):
            ind = i+1-self.N0
            if ind >= N:
                self.nodes[i].val = default_value
            elif ind >=0 and N > ind:
                self.nodes[i].val = vals[ind]
            else:
                self.nodes[i] = self.process(
                    self.nodes[i*2+1], self.nodes[i*2+2])

    def __getitem__(self, key):  # getiten : ST[i]
        return self.nodes[key+self.N0-1].val

    def __setitem__(self, i, x):  # update : ST[i] = x
        i += self.N0 - 1
        self.nodes[i].val = x
        while i > 0:
            i = (i-1)//2
            self.nodes[i] = self.process(self.nodes[i*2+1], self.nodes[i*2+2])

    def __str__(self):
        return '['+', '.join(map(str, [self.nodes[i+self.N0-1].val for i in range(self.N0)]))+']'

    def query(self, L, R):  # [L,R)の値
        retnode = Node(0, 0)
        L += self.N0
        R += self.N0
        while L < R:
            if R & 1:
                R -= 1
                retnode = self.process(retnode, self.nodes[R-1])
            if L & 1:
                retnode = self.process(retnode, self.nodes[L-1])
                L += 1
            L >>= 1
            R >>= 1
        return retnode

    def process(self, node_x, node_y):  # x,yが子の時，親に返る値
        return Node(node_x.val | node_y.val)


def main():
    N = iRaw()
    S = sRaw()
    sgt = SegmentTree(N, [1 << (ord(s)-ord('a')) for s in S])
    Q = iRaw()
    ans =[]
    for _ in range(Q):
        t,l,r = ssRaw()
        if t=="1":
            sgt[int(l)-1] = 1 << (ord(r)-ord("a"))
        else:
            ret = sgt.query(int(l)-1, int(r))
            ans.append(str(bin(ret.val)).count("1"))
    return "\n".join(map(str, ans))

if __name__ == "__main__":
    print(main())