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 in PyPy3 (2.4.0) (judge verdict: Accepted)

import sys
from collections import *
import heapq
import math
import bisect
from itertools import permutations,accumulate,combinations,product
from fractions import gcd
import copy
def input():
    return sys.stdin.readline()[:-1]
def ruiseki(lst):
    return [0]+list(accumulate(lst))
mod=pow(10,9)+7

n=int(input())
s=input()
q=int(input())
qlst=[list(input().split()) for i in range(q)]

lst=[0]*n

for i in range(n):
    lst[i] = pow(2,(ord(s[i])-ord("a")))

# print(lst)
#####segfunc######
# def segfunc(x,y):
#     return x|y
 
# def init(init_val): #渡されたリストでsegを初期化
#     #set_val
#     for i in range(n):
#         seg[i+num-1]=init_val[i]
#     #built
#     for i in range(num-2,-1,-1) :
#         seg[i]=segfunc(seg[2*i+1],seg[2*i+2]) 
    
# def update(k,x): #segの要素kをxに変更(セグ木全体の更新)
#     k += num-1
#     seg[k] = x
#     while k:
#         k = (k-1)//2
#         seg[k] = segfunc(seg[k*2+1],seg[k*2+2])
    
# def query(p,q): #区間[p,q)での、segfuncに準じた値を返す
#     if q<=p:
#         return ide_ele
#     p += num-1
#     q += num-2
#     res=ide_ele
#     while q-p>1:
#         if p&1 == 0:
#             res = segfunc(res,seg[p])
#         if q&1 == 1:
#             res = segfunc(res,seg[q])
#             q -= 1
#         p = p//2
#         q = (q-1)//2
#     if p == q:
#         res = segfunc(res,seg[p])
#     else:
#         res = segfunc(segfunc(res,seg[p]),seg[q])
#     return res
 
# #####単位元######
# """
# 最小値のセグ木 → 10**9　(最小値の更新に影響しないため)
# 　　和のセグ木 → 0　(上の単位元の説明を参照)
# 　　積のセグ木 → 1　(上の単位元の説明を参照)
# 　　gcdのセグ木 → 0　(gcdを更新しない値は0)
# """
# ide_ele = 0
 
# #num:n以上の最小の2のべき乗
# num =2**(n-1).bit_length()
# seg=[ide_ele]*2*num #単位元の配列(計算結果に影響を及ぼさない配列)を作成
 
class SegTree:
    def __init__(self, init_val, i_e):
        self.ide_ele=i_e
        self.num=2**(len(init_val)-1).bit_length()
        self.seg=[self.ide_ele]*2*self.num

        #set_val
        for i in range(len(init_val)):
            self.seg[i+self.num-1]=init_val[i]
        #built
        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 segfunc(self, x, y):
        return x|y
    
    def update(self, k, x):
        k += self.num-1
        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

seg=SegTree(lst, 0)

def judge(u):
    res = 0
    for i in range(27):
        if u>>i & 1:
            res += 1
    return res
 
for i in range(q):
    t,x,y = qlst[i]
    if t == "1":
        seg.update(int(x)-1,pow(2,ord(y)-ord("a")))
    else:
        print(judge(seg.query(int(x)-1,int(y))))