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):
import sys
from collections import deque
import bisect
import copy
import heapq
import itertools
import math
input = sys.stdin.readline
sys.setrecursionlimit(1000000)
mod = 10 ** 9 + 7

def read_values(): return map(int, input().split())
def read_index(): return map(lambda x: int(x) - 1, input().split())
def read_list(): return list(read_values())
def read_lists(N): return [read_list() for n in range(N)]


def _get(T, a, b, k, l, r):
    if r <= a or b <= l:
        return set()

    if a <= l and r <= b:
        return T[k]
    else:
        s1 = _get(T, a, b, 2 * k + 1, l, (l + r) // 2)
        s2 = _get(T, a, b, 2 * k + 2, (l + r) // 2, r)
        return s1.union(s2)


def get(T, d, a, b):
    return _get(T, a, b, 0, 0, 2 ** d)


def main():
    N = int(input())
    S = input().strip()
    Q = [input().strip().split() for _ in range(int(input()))]
    d = N.bit_length()
    T = [set() for _ in range(2 ** (d + 1) - 1)]
    for i, s in enumerate(S):
        T[i + 2 ** d - 1].add(s)
    for i in range(2 ** d - 2, -1, -1):
        T[i] =T[2 * i + 1] .union(T[2 * i + 2])

    for s, a, b in Q:
        if s == "1":
            a = int(a) - 1
            i = a + 2 ** d - 1
            if b in T[i]:
                continue
            T[i] = {b}
            while i > 0:
                i = (i - 1) // 2
                T[i] = T[2 * i + 1] .union(T[2 * i + 2])
        elif s == "2":
            a = int(a) - 1
            b = int(b) - 1
            S = get(T, d, a, b + 1)
            print(len(S))


if __name__ == "__main__":
    main()

Solution (Python):

class Bit:
    """ used for only int(>=0) 
        1-indexed (ignore 0-index)
    """
    def __init__(self, n):
        self.size = n
        self.tree = [0] * (n + 1)
        self.depth = n.bit_length()
 
    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

    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 get_less_than_x_cnt(self, x):
        """ 累積和がx未満 の個数 """
        lb_pos, lb_sum = self.lower_bound(x)
        return lb_pos-1

    def get_less_than_and_x_cnt(self, x):
        """ 累積和がx以下 の個数 """
        lb_pos, lb_sum = self.lower_bound(x+1)
        return lb_pos-1
    
    def get_more_than_x_cnt(self, x):
        """ 累積和がxより大きい 個数 """
        return self.size - self.get_less_than_and_x_cnt(x)


def main():
    n = int(input())
    s = list(input())
    q = int(input())
    alps = 'abcdefghijklmnopqrstuvwxyz'

    
    alp_d = {chr(ord('a') + i): Bit(n) for i in range(26)}
    for i,si in enumerate(s):
        alp_d[si].add(i+1,1) 

    ansl = []
    for i in range(q):
        com,a,b = map(str, input().split())
        if com == '1':
            i,c = int(a),b
            si = s[i-1]
            alp_d[si].add(i, -1)
            alp_d[c].add(i, 1)
            s[i-1] = c
        else:
            l,r = int(a),int(b)
            ans = 0
            for alp in alps:
                cnt = alp_d[alp].sum(r) - alp_d[alp].sum(l-1)
                if cnt > 0:
                    ans+=1
            ansl.append(ans)

    for a in ansl:
        print(a)


if __name__ == "__main__":
    main()

Solution (Python):
import sys
input = sys.stdin.readline
N = int(input())
S = input().rstrip()
Q = int(input())
qs = [input().split() for i in range(Q)]

class BinaryIndexedTree:
    def __init__(self,size):
        self.N = size
        self.bit = [0]*(size+1)
    def add(self,x,w): 
        x += 1
        while x <= self.N:
            self.bit[x] += w
            x += (x & -x)
    def _sum(self,x): 
        ret = 0
        while x > 0:
            ret += self.bit[x]
            x -= (x & -x)
        return ret
    def sum(self,l,r): 
        return self._sum(r) - self._sum(l)
    def __str__(self): 
        arr = [self.sum(i,i+1) for i in range(self.N)]
        return str(arr)

bits = [BinaryIndexedTree(N+1) for i in range(26)]
for i,c in enumerate(S):
    ci = ord(c) - ord('a')
    bits[ci].add(i,1)
now = list(S)

for a,b,c in qs:
    if a=='1':
        b = int(b)
        pi = ord(now[b-1]) - ord('a')
        bits[pi].add(b-1, -1)
        ci = ord(c) - ord('a')
        bits[ci].add(b-1, 1)
        now[b-1] = c
    else:
        b,c = int(b),int(c)
        cnt = 0
        for i in range(26):
            cnt += int(bits[i].sum(b-1,c) > 0)
        print(cnt)

Solution (Python):
n = int(input())
S = list(str(input()))
S = [{ord(c)-ord('a')} for c in S]

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

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

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

def query(p, q):
    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


ide_ele = set()


num = 2**(n-1).bit_length()
seg = [ide_ele]*2*num

init(S)

import sys
input = sys.stdin.readline
q = int(input())
for i in range(q):
    t, x, y = map(str, input().split())
    if t == '1':
        x = int(x)
        y = ord(y)-ord('a')
        update(x-1, {y})
    else:
        x = int(x)
        y = int(y)
        print(len(query(x-1, y)))

Solution (Python):

from collections import defaultdict, deque, Counter, OrderedDict
from bisect import bisect_left, bisect_right
from functools import reduce, lru_cache
from heapq import heappush, heappop, heapify

import itertools, bisect
import math, fractions
import sys, copy

def L(): return sys.stdin.readline().split()
def I(): return int(sys.stdin.readline().rstrip())
def S(): return list(sys.stdin.readline().rstrip())
def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LI1(): return [int(x) - 1 for x in sys.stdin.readline().split()]
def LS(): return [list(x) for x in sys.stdin.readline().split()]
def IR(n): return [I() for _ in range(n)]
def LIR(n): return [LI() for _ in range(n)]
def LIR1(n): return [LI1() for _ in range(n)]
def SR(n): return [S() for _ in range(n)]
def LSR(n): return [LS() for _ in range(n)]
def LR(n): return [L() for _ in range(n)]

alphabets = "abcdefghijklmnopqrstuvwxyz"

sys.setrecursionlimit(1000000)
dire = [[1, 0], [0, 1], [-1, 0], [0, -1]]
dire8 = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]
MOD = 1000000007



import pprint

class BalancingTree:
    def __init__(self, n):
        self.N = n
        self.root = self.node(1<<n, 1<<n)

    def __str__(self):
        def debug_info(nd):
            return (nd.value - 1, nd.left.value - 1 if nd.left else None, nd.right.value - 1 if nd.right else None)

        def debug_node(nd):
            v = debug_info(nd) if nd.value else ()
            left = debug_node(nd.left) if nd.left else []
            right = debug_node(nd.right) if nd.right else []
            return [v, left, right]

        return pprint.PrettyPrinter(indent=4).pformat(debug_node(self.root))

    __repr__ = __str__

    def append(self, 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):
        return self.leftmost(nd.left) if nd.left else nd

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

    def find_l(self, v): 
        v += 1
        nd = self.root
        prev = nd.value if nd.value < v else 0
        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 += 1
        nd = self.root
        prev = nd.value if nd.value > v else 0
        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

    def max(self):
        return self.find_l((1<<self.N)-1)

    def min(self):
        return self.find_r(-1)

    def delete(self, v, nd = None, prev = None): 
        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 upper_bound(self, v):
        upper = self.find_r(v)
        return self.find_l(upper)

    def lower_bound(self, v):
        lower = self.find_l(v)
        return self.find_r(lower)

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

    class node:
        def __init__(self, v, p):
            self.value = v
            self.pivot = p
            self.left = None
            self.right = None

def main():
    N = I()
    s = S()
    Q = I()
    query = LR(Q)

    trees = {ch: BalancingTree(25) for ch in alphabets}

    for i, ch in enumerate(s):
        trees[ch].append(i)

    for q in query:
        if q[0] == "1":
            _, i, c = q
            i = int(i) - 1
            prev = s[i]
            trees[prev].delete(i)
            s[i] = c
            trees[c].append(i)
        else:
            _, l, r = q
            l, r = int(l) - 1, int(r) - 1
            count = 0
            for _, tree in trees.items():
                first = tree.lower_bound(l)
                if first != tree.root.value - 1 and first <= r:
                    count += 1
            print(count)



if __name__ == '__main__':
    main()

Solution (Python):






import sys
input = sys.stdin.readline

import math

import bisect
import heapq
from collections import defaultdict
from collections import deque
from collections import Counter
from functools import lru_cache





MOD = 10**9+7
INF = float('inf')
AZ = "abcdefghijklmnopqrstuvwxyz"






def I(): return int(input().strip())
def S(): return input().strip()
def IL(): return list(map(int,input().split()))
def SL(): return list(map(str,input().split()))
def ILs(n): return list(int(input()) for _ in range(n))
def SLs(n): return list(input().strip() for _ in range(n))
def ILL(n): return [list(map(int, input().split())) for _ in range(n)]
def SLL(n): return [list(map(str, input().split())) for _ in range(n)]


def P(arg): print(arg); return
def Y(): print("Yes"); return
def N(): print("No"); return
def E(): exit()
def PE(arg): print(arg); exit()
def YE(): print("Yes"); exit()
def NE(): print("No"); exit()


def DD(arg): return defaultdict(arg)


def inv(n): return pow(n, MOD-2, MOD)


kaijo_memo = []
def kaijo(n):
  if(len(kaijo_memo) > n): return kaijo_memo[n]
  if(len(kaijo_memo) == 0): kaijo_memo.append(1)
  while(len(kaijo_memo) <= n): kaijo_memo.append(kaijo_memo[-1] * len(kaijo_memo) % MOD)
  return kaijo_memo[n]

gyaku_kaijo_memo = []
def gyaku_kaijo(n):
  if(len(gyaku_kaijo_memo) > n): return gyaku_kaijo_memo[n]
  if(len(gyaku_kaijo_memo) == 0): gyaku_kaijo_memo.append(1)
  while(len(gyaku_kaijo_memo) <= n): gyaku_kaijo_memo.append(gyaku_kaijo_memo[-1] * pow(len(gyaku_kaijo_memo),MOD-2,MOD) % MOD)
  return gyaku_kaijo_memo[n]

def nCr(n,r):
  if n == r: return 1
  if n < r or r < 0: return 0
  ret = 1
  ret = ret * kaijo(n) % MOD
  ret = ret * gyaku_kaijo(r) % MOD
  ret = ret * gyaku_kaijo(n-r) % MOD
  return ret


def factorization(n):
  arr = []
  temp = n
  for i in range(2, int(-(-n**0.5//1))+1):
    if temp%i==0:
      cnt=0
      while temp%i==0: 
        cnt+=1 
        temp //= i
      arr.append([i, cnt])
  if temp!=1: arr.append([temp, 1])
  if arr==[]: arr.append([n, 1])
  return arr


def make_divisors(n):
  divisors = []
  for i in range(1, int(n**0.5)+1):
    if n % i == 0:
      divisors.append(i)
      if i != n // i: 
        divisors.append(n//i)
  return divisors


def make_primes(N):
  max = int(math.sqrt(N))
  seachList = [i for i in range(2,N+1)]
  primeNum = []
  while seachList[0] <= max:
    primeNum.append(seachList[0])
    tmp = seachList[0]
    seachList = [i for i in seachList if i % tmp != 0]
  primeNum.extend(seachList)
  return primeNum


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


def lcm(a, b):
    return a * b // gcd (a, b)


def count_bit(n):
  count = 0
  while n:
    n &= n-1
    count += 1
  return count


def base_10_to_n(X, n):
  if X//n: return base_10_to_n(X//n, n)+[X%n]
  return [X%n]

def base_n_to_10(X, n):
  return sum(int(str(X)[-i-1])*n**i for i in range(len(str(X))))

def base_10_to_n_without_0(X, n):
  X -= 1
  if X//n: return base_10_to_n_without_0(X//n, n)+[X%n]
  return [X%n]


def int_log(n, a):
  count = 0
  while n>=a:
    n //= a
    count += 1
  return count




class BIT:
  def __init__(self, logn):
    self.n = 1<<logn
    self.data = [0]*(self.n+1)
    self.el = [0]*(self.n+1)
  def sum(self, i):
    s = 0
    while i > 0:
      s += self.data[i]
      i -= i & -i
    return s
  def add(self, i, x):
    
    self.el[i] += x
    while i <= self.n:
      self.data[i] += x
      i += i & -i
  def get(self, i, j=None):
    if j is None:
      return self.el[i]
    return self.sum(j) - self.sum(i)
  def bisect(self, x):
    w = i = 0
    k = self.n
    while k:
      if i+k <= self.n and w + self.data[i+k] <= x:
        w += self.data[i+k]
        i += k
      k >>= 1
    return i+1

N = I()
A = list(S())
Q = I()

dic = {l:BIT(int_log(N,2)+1) for l in AZ}

for i in range(N):
  s = A[i]
  dic[s].add(i+1,1)

def change(i,y):
  prev = A[i-1]
  if prev == y:
    pass
  else:
    A[i-1] = y
    dic[prev].add(i,-1)
    dic[y].add(i,1)
  
def count(x,y):
  ret = 0
  for l in AZ:
    if dic[l].sum(x-1) != dic[l].sum(y):
      ret += 1
  print(ret)

for _ in range(Q):
  t,x,y = SL()
  if t == "1":
    change(int(x),y)
  else:
    count(int(x),int(y))

Solution (Python):






import sys
input = sys.stdin.readline

import math

import bisect
import heapq
from collections import defaultdict
from collections import deque
from collections import Counter
from functools import lru_cache





MOD = 10**9+7
INF = float('inf')
AZ = "abcdefghijklmnopqrstuvwxyz"






def I(): return int(input().strip())
def S(): return input().strip()
def IL(): return list(map(int,input().split()))
def SL(): return list(map(str,input().split()))
def ILs(n): return list(int(input()) for _ in range(n))
def SLs(n): return list(input().strip() for _ in range(n))
def ILL(n): return [list(map(int, input().split())) for _ in range(n)]
def SLL(n): return [list(map(str, input().split())) for _ in range(n)]


def P(arg): print(arg); return
def Y(): print("Yes"); return
def N(): print("No"); return
def E(): exit()
def PE(arg): print(arg); exit()
def YE(): print("Yes"); exit()
def NE(): print("No"); exit()


def DD(arg): return defaultdict(arg)


def inv(n): return pow(n, MOD-2, MOD)


kaijo_memo = []
def kaijo(n):
  if(len(kaijo_memo) > n): return kaijo_memo[n]
  if(len(kaijo_memo) == 0): kaijo_memo.append(1)
  while(len(kaijo_memo) <= n): kaijo_memo.append(kaijo_memo[-1] * len(kaijo_memo) % MOD)
  return kaijo_memo[n]

gyaku_kaijo_memo = []
def gyaku_kaijo(n):
  if(len(gyaku_kaijo_memo) > n): return gyaku_kaijo_memo[n]
  if(len(gyaku_kaijo_memo) == 0): gyaku_kaijo_memo.append(1)
  while(len(gyaku_kaijo_memo) <= n): gyaku_kaijo_memo.append(gyaku_kaijo_memo[-1] * pow(len(gyaku_kaijo_memo),MOD-2,MOD) % MOD)
  return gyaku_kaijo_memo[n]

def nCr(n,r):
  if n == r: return 1
  if n < r or r < 0: return 0
  ret = 1
  ret = ret * kaijo(n) % MOD
  ret = ret * gyaku_kaijo(r) % MOD
  ret = ret * gyaku_kaijo(n-r) % MOD
  return ret


def factorization(n):
  arr = []
  temp = n
  for i in range(2, int(-(-n**0.5//1))+1):
    if temp%i==0:
      cnt=0
      while temp%i==0: 
        cnt+=1 
        temp //= i
      arr.append([i, cnt])
  if temp!=1: arr.append([temp, 1])
  if arr==[]: arr.append([n, 1])
  return arr


def make_divisors(n):
  divisors = []
  for i in range(1, int(n**0.5)+1):
    if n % i == 0:
      divisors.append(i)
      if i != n // i: 
        divisors.append(n//i)
  return divisors


def make_primes(N):
  max = int(math.sqrt(N))
  seachList = [i for i in range(2,N+1)]
  primeNum = []
  while seachList[0] <= max:
    primeNum.append(seachList[0])
    tmp = seachList[0]
    seachList = [i for i in seachList if i % tmp != 0]
  primeNum.extend(seachList)
  return primeNum


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


def lcm(a, b):
    return a * b // gcd (a, b)


def count_bit(n):
  count = 0
  while n:
    n &= n-1
    count += 1
  return count


def base_10_to_n(X, n):
  if X//n: return base_10_to_n(X//n, n)+[X%n]
  return [X%n]

def base_n_to_10(X, n):
  return sum(int(str(X)[-i-1])*n**i for i in range(len(str(X))))

def base_10_to_n_without_0(X, n):
  X -= 1
  if X//n: return base_10_to_n_without_0(X//n, n)+[X%n]
  return [X%n]


def int_log(n, a):
  count = 0
  while n>=a:
    n //= a
    count += 1
  return count




class BIT:
  def __init__(self, logn):
    self.n = 1<<logn
    self.data = [0]*(self.n+1)
    self.el = [0]*(self.n+1)
  def sum(self, i):
    s = 0
    while i > 0:
      s += self.data[i]
      i -= i & -i
    return s
  def add(self, i, x):
    
    self.el[i] += x
    while i <= self.n:
      self.data[i] += x
      i += i & -i
  def get(self, i, j=None):
    if j is None:
      return self.el[i]
    return self.sum(j) - self.sum(i)
  def bisect(self, x):
    w = i = 0
    k = self.n
    while k:
      if i+k <= self.n and w + self.data[i+k] <= x:
        w += self.data[i+k]
        i += k
      k >>= 1
    return i+1

N = I()
A = list(S())
Q = I()

dic = {l:BIT(int_log(N,2)+1) for l in AZ}

for i in range(N):
  s = A[i]
  dic[s].add(i+1,1)

def change(i,y):
  prev = A[i]
  if prev == y:
    pass
  else:
    A[i] = y
    dic[prev].add(i+1,-1)
    dic[y].add(i+1,1)
  
def count(x,y):
  ret = 0
  for l in AZ:
    if dic[l].sum(x) != dic[l].sum(y):
      ret += 1
  print(ret)

for _ in range(Q):
  t,x,y = SL()
  if t == "1":
    change(int(x)-1,y)
  else:
    count(int(x)-1,int(y))

Solution (Python):
n=int(input())
s=[*input()]
q=int(input())
from collections import *
d=defaultdict(list)
for i,c in enumerate(s):
  d[c]+=[i]
from bisect import *
for _ in range(q):
  x,y,z=input().split()
  y=int(y)-1
  if x=='1':
    if s[y]==z: continue
    d[s[y]].pop(bisect(d[s[y]],y)-1)
    s[y]=z
    insort(d[z],y)
  else:
    print(sum(bisect(l,int(z)-1)-bisect_left(l,y)>0 for l in d.values()))

Solution (Python):
n=int(input())
s=[*input()]
q=int(input())
from collections import *
d=defaultdict(list)
from bisect import *
for i,c in enumerate(s):
  d[c]+=[i]
for _ in range(q):
  x,y,z=input().split()
  y=int(y)-1
  if x=='1':
    if s[y]==z: continue
    d[s[y]].pop(bisect(d[s[y]],y)-1)
    s[y]=z
    insort(d[z],y)
  else:
    a=0
    for l in d.values():
      if bisect(l,int(z)-1)-bisect_left(l,y): a+=1
    print(a)

Solution (Python):
n=int(input())
s=[*input()]
q=int(input())

B={chr(97+i):[0]*(n+1) for i in range(26)}
def bsum(c,i):
  s=0
  while i:
    s+=B[c][i]
    i-=i&-i
  return s
def badd(c,i,x):
  while i<=n:
    B[c][i]+=x
    i+=i&-i
for i,c in enumerate(s):
  badd(c,i+1,1)
for _ in range(q):
  x,y,z=input().split()
  y=int(y)-1
  if x=='1':
    badd(s[y],y+1,-1)
    s[y]=z
    badd(z,y+1,1)
  else:
    print(sum(1 for c in B if bsum(c,int(z))-bsum(c,y)))

Solution (Python):
n=int(input())
s=[*input()]
q=int(input())

B={chr(97+i):[0]*(n+1) for i in range(26)}
def bsum(c,i):
  s=0
  while i:
    s+=B[c][i]
    i-=i&-i
  return s
def badd(c,i,x):
  while i<=n:
    B[c][i]+=x
    i+=i&-i
for i,c in enumerate(s):
  badd(c,i+1,1)
for _ in range(q):
  x,y,z=input().split()
  y=int(y)-1
  if x=='1':
    badd(s[y],y+1,-1)
    s[y]=z
    badd(z,y+1,1)
  else:
    print(sum(bsum(c,int(z))-bsum(c,y)>0 for c in B))

Solution (Python):
n=int(input())
s=[*input()]
q=int(input())

B={chr(97+i):[0]*(n+1) for i in range(26)}
def bsum(c,i):
  s=0
  while i:
    s+=B[c][i]
    i-=i&-i
  return s
def badd(c,i,x):
  while i<=n:
    B[c][i]+=x
    i+=i&-i
for i,c in enumerate(s):
  badd(c,i+1,1)
for _ in range(q):
  x,y,z=input().split()
  y=int(y)-1
  if x=='1':
    badd(s[y],y+1,-1)
    s[y]=z
    badd(z,y+1,1)
  else:
    a=0
    for c in B:
      if bsum(c,int(z))-bsum(c,y): a+=1
    print(a)