Buggy python submission (verdict: Time Limit Exceeded):
import sys
input = sys.stdin.readline

N = int(input())
S = list(input().rstrip())
ord_a = ord("a")

# N: 処理する区間の長さ
INF = 2**31-1

LV = (N-1).bit_length()
N0 = 2**LV
data = [[0]*(2*N0) for _ in range(26)]
lazy = [[0]*(2*N0) for _ in range(26)]

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(k, *ids):
    for i in reversed(ids):
        v = lazy[k][i-1]
        if not v:
            continue
        lazy[k][2*i-1] += v; lazy[k][2*i] += v
        data[k][2*i-1] += v; data[k][2*i] += v
        lazy[k][i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x, k):
    *ids, = gindex(l, r)
    propagates(k, *ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[k][R-1] += x; data[k][R-1] += x
        if L & 1:
            lazy[k][L-1] += x; data[k][L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[k][i-1] = max(data[k][2*i-1], data[k][2*i])

# 区間[l, r)内の最大値を求める
def query(l, r, k):
    propagates(k, *gindex(l, r))
    L = N0 + l; R = N0 + r

    s = -INF
    while L < R:
        if R & 1:
            R -= 1
            s = max(s, data[k][R-1])
        if L & 1:
            s = max(s, data[k][L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for j in range(N):
    u = S[j]
    update(j, N, 1, ord(u) - ord_a)

Q = int(input())

for _ in range(Q):
    q = input().rstrip().split()
    if q[0] == "2":
        l, r = int(q[1]) - 1, int(q[2]) - 1
        cnt = 0
        for i in range(26):
            if l == 0:
                cnt += int(query(r, r + 1, i) > 0)
            else:
                cnt += int((query(r, r + 1, i) - query(l - 1, l, i) > 0))

        print(cnt)
    else:
        i, c = int(q[1]) - 1, q[2]
        update(i, N, -1, ord(S[i]) - ord_a)
        S[i] = c
        update(i, N, 1, ord(S[i]) - ord_a)

Fixed submission:
import sys
input = sys.stdin.readline

N = int(input())
S = list(input().rstrip())
ord_a = ord("a")

class Bit:
    def __init__(self, n):
        self.size = n
        self.tree = [0] * (n + 1)
 
    def sum(self, i):
        s = 0
        while i > 0:
            s += self.tree[i]
            i -= i & -i
        return s
 
    def add(self, i, x):
        while i <= self.size:
            self.tree[i] += x
            i += i & -i

bits = [Bit(N) for _ in range(26)]

for i in range(N):
    s = S[i]
    bits[ord(s) - ord_a].add(i + 1, 1)

Q = int(input())

for _ in range(Q):
    query = input().rstrip().split()
    if query[0] == "1":
        i, c = int(query[1]), query[2]
        bits[ord(S[i - 1]) - ord_a].add(i, -1)
        S[i - 1] = c
        bits[ord(S[i - 1]) - ord_a].add(i, 1)
    else:
        l, r = int(query[1]), int(query[2])
        res = 0
        for bit in bits:
            if l != 1:
                res += int(bit.sum(r) - bit.sum(l - 1) > 0)
            else:
                res += int(bit.sum(r) > 0)
        print(res)

Buggy python submission (verdict: Time Limit Exceeded):
import sys
input = sys.stdin.readline

N = int(input())
S = list(input().rstrip())
ord_a = ord("a")

# N: 処理する区間の長さ
INF = 2**31-1

LV = (N-1).bit_length()
N0 = 2**LV
data = [[0]*(2*N0) for _ in range(26)]
lazy = [[0]*(2*N0) for _ in range(26)]

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(k, *ids):
    for i in reversed(ids):
        v = lazy[k][i-1]
        if not v:
            continue
        lazy[k][2*i-1] += v; lazy[k][2*i] += v
        data[k][2*i-1] += v; data[k][2*i] += v
        lazy[k][i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x, k):
    *ids, = gindex(l, r)
    propagates(k, *ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[k][R-1] += x; data[k][R-1] += x
        if L & 1:
            lazy[k][L-1] += x; data[k][L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[k][i-1] = max(data[k][2*i-1], data[k][2*i])

# 区間[l, r)内の最大値を求める
def query(l, r, k):
    propagates(k, *gindex(l, r))
    L = N0 + l; R = N0 + r

    s = -INF
    while L < R:
        if R & 1:
            R -= 1
            s = max(s, data[k][R-1])
        if L & 1:
            s = max(s, data[k][L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for j in range(N):
    u = S[j]
    update(j, N, 1, ord(u) - ord_a)

Q = int(input())

for _ in range(Q):
    q = input().rstrip().split()
    if q[0] == "2":
        l, r = int(q[1]) - 1, int(q[2]) - 1
        cnt = 0
        for i in range(26):
            if l == 0:
                cnt += int(query(r, r + 1, i) > 0)
            else:
                cnt += int((query(r, r + 1, i) - query(l - 1, l, i) > 0))
        print(cnt)
    else:
        i, c = int(q[1]) - 1, q[2]
        update(i, N, -1, ord(S[i]) - ord_a)
        S[i] = c
        update(i, N, 1, ord(S[i]) - ord_a)

Fixed submission:
import sys
input = sys.stdin.readline

N = int(input())
S = list(input().rstrip())
ord_a = ord("a")

class Bit:
    def __init__(self, n):
        self.size = n
        self.tree = [0] * (n + 1)
 
    def sum(self, i):
        s = 0
        while i > 0:
            s += self.tree[i]
            i -= i & -i
        return s
 
    def add(self, i, x):
        while i <= self.size:
            self.tree[i] += x
            i += i & -i

bits = [Bit(N) for _ in range(26)]

for i in range(N):
    s = S[i]
    bits[ord(s) - ord_a].add(i + 1, 1)

Q = int(input())

for _ in range(Q):
    query = input().rstrip().split()
    if query[0] == "1":
        i, c = int(query[1]), query[2]
        bits[ord(S[i - 1]) - ord_a].add(i, -1)
        S[i - 1] = c
        bits[ord(S[i - 1]) - ord_a].add(i, 1)
    else:
        l, r = int(query[1]), int(query[2])
        res = 0
        for bit in bits:
            if l != 1:
                res += int(bit.sum(r) - bit.sum(l - 1) > 0)
            else:
                res += int(bit.sum(r) > 0)
        print(res)

Buggy python submission (verdict: Runtime Error):
import sys
input = sys.stdin.readline

N = int(input())
S = list(input().rstrip())
ord_a = ord("a")

# N: 処理する区間の長さ
INF = 2**31-1

LV = (N-1).bit_length()
N0 = 2**LV
data = [[0]*(2*N0) for _ in range(26)]
lazy = [[0]*(2*N0) for _ in range(26)]

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

# 遅延伝搬処理
def propagates(k, *ids):
    for i in reversed(ids):
        v = lazy[k][i-1]
        if not v:
            continue
        lazy[k][2*i-1] += v; lazy[k][2*i] += v
        data[k][2*i-1] += v; data[k][2*i] += v
        lazy[k][i-1] = 0

# 区間[l, r)にxを加算
def update(l, r, x, k):
    *ids, = gindex(l, r)
    propagates(k, *ids)

    L = N0 + l; R = N0 + r
    while L < R:
        if R & 1:
            R -= 1
            lazy[k][R-1] += x; data[k][R-1] += x
        if L & 1:
            lazy[k][L-1] += x; data[k][L-1] += x
            L += 1
        L >>= 1; R >>= 1
    for i in ids:
        data[k][i-1] = max(data[k][2*i-1], data[k][2*i])

# 区間[l, r)内の最大値を求める
def query(l, r, k):
    propagates(k, *gindex(l, r))
    L = N0 + l; R = N0 + r

    s = -INF
    while L < R:
        if R & 1:
            R -= 1
            s = max(s, data[k][R-1])
        if L & 1:
            s = max(s, data[k][L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

for j in range(N):
    u = S[j]
    update(j, N, 1, ord(u) - ord_a)

Q = int(input())

for _ in range(Q):
    q = input().rstrip().split()
    if q[0] == "2":
        l, r = int(q[1]) - 1, int(q[2]) - 1
        cnt = 0
        for i in range(26):
            if l == 0:
                cnt += int(query(r, r + 1, i) > 0)
            else:
                cnt += int((query(r, r + 1, i) - query(l - 1, l, i) > 0))
        print(cnt)
    else:
        i, c = int(q[1]) - 1, q[2]
        update(l, N, -1, ord(S[i]) - ord_a)
        S[i] = c
        update(l, N, 1, ord(S[i]) - ord_a)

Fixed submission:
import sys
input = sys.stdin.readline

N = int(input())
S = list(input().rstrip())
ord_a = ord("a")

class Bit:
    def __init__(self, n):
        self.size = n
        self.tree = [0] * (n + 1)
 
    def sum(self, i):
        s = 0
        while i > 0:
            s += self.tree[i]
            i -= i & -i
        return s
 
    def add(self, i, x):
        while i <= self.size:
            self.tree[i] += x
            i += i & -i

bits = [Bit(N) for _ in range(26)]

for i in range(N):
    s = S[i]
    bits[ord(s) - ord_a].add(i + 1, 1)

Q = int(input())

for _ in range(Q):
    query = input().rstrip().split()
    if query[0] == "1":
        i, c = int(query[1]), query[2]
        bits[ord(S[i - 1]) - ord_a].add(i, -1)
        S[i - 1] = c
        bits[ord(S[i - 1]) - ord_a].add(i, 1)
    else:
        l, r = int(query[1]), int(query[2])
        res = 0
        for bit in bits:
            if l != 1:
                res += int(bit.sum(r) - bit.sum(l - 1) > 0)
            else:
                res += int(bit.sum(r) > 0)
        print(res)