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

sys.setrecursionlimit(10 ** 6)
int1 = lambda x: int(x) - 1
p2D = lambda x: print(*x, sep="\n")
def II(): return int(sys.stdin.readline())
def MI(): return map(int, sys.stdin.readline().split())
def LI(): return list(map(int, sys.stdin.readline().split()))
def LLI(rows_number): return [LI() for _ in range(rows_number)]
def SI(): return sys.stdin.readline()[:-1]

class BitSum:
    def __init__(self, n):
        self.n = n + 3
        self.table = [0] * (self.n + 1)

    def add(self, i, x):
        i += 1
        while i <= self.n:
            self.table[i] += x
            i += i & -i

    def sum(self, i):
        i += 1
        res = 0
        while i > 0:
            res += self.table[i]
            i -= i & -i
        return res

def main():
    n = II()
    bits = [BitSum(n) for _ in range(26)]
    s = list(SI())
    a = ord("a")
    for i, c in enumerate(s):
        code = ord(c) - a
        bits[code].add(i, 1)
    q = II()
    for _ in range(q):
        op, x, y = input().split()
        if op == "1":
            i = int(x) - 1
            now = s[i]
            s[i] = y
            bits[ord(now) - a].add(i, -1)
            bits[ord(y) - a].add(i, 1)
        else:
            l, r = int(x) - 2, int(y) - 1
            print(sum(bits[i].sum(r) - bits[i].sum(l) > 0 for i in range(26)))

main()

Solution (Python):
import bisect

N = int(input())
S = input()
Q = int(input())
alphabet_dic = {}
alphabet_array = []
for i,s in enumerate(S):
    alphabet_array.append(s)
    if s in alphabet_dic:
        alphabet_dic[s].append(i)
    else:
        alphabet_dic[s] = [i]


for _ in range(Q):
    a, b, c = map(str,input().split())
    if int(a) == 1:
        b = int(b)
        now_str = alphabet_array[b-1]
        if now_str != c:
            alphabet_array[b-1] = c
            alphabet_dic[now_str].remove(b-1)
            if c in alphabet_dic:
                bisect.insort_left(alphabet_dic[c],b-1)
            else:
                alphabet_dic[c] = [b-1]
    else:
        ans = 0
        b = int(b)
        c = int(c)
        for index_array in alphabet_dic.values():
            if not len(index_array) or index_array[-1] < b-1:
                continue
            i = bisect.bisect_left(index_array,b-1)
            if index_array[i] <= c-1:
                ans += 1
        print(ans)

Solution (Python):

"""
Created on Sat Jun 15 22:01:38 2019

@author: aozora
"""
class BIT:
  def __init__(self,n):
    self.N = n
    self.data = [0]*(N+1)
  def bit_add(self,i,a):
    j = i+1
    while j<=N:
      self.data[j] += a
      j += j&-j
  def bit_sum(self,i):
    m = 0
    j = i+1
    while j>0:
      m += self.data[j]
      j -= j&-j
    return m
N = int(input())
S = list(input())
Q = int(input())
dic = [0]*26
s = ord('a')
for i in range(26):
  dic[i] = BIT(N)
for i, c in enumerate(S):
  c = ord(c)-s
  dic[c].bit_add(i,1)
for i in range(Q):
  t, a, b = input().split()
  t = int(t)
  if t==1:
    a = int(a)-1
    c = S[a]
    S[a] = b
    b = ord(b)-s
    c = ord(c)-s
    dic[b].bit_add(a,1)
    dic[c].bit_add(a,-1)
  else:
    a = int(a)
    b = int(b)
    ans = 0
    a -= 1
    b -= 1
    for i in range(26):
      if a>0:
        z = dic[i].bit_sum(b)-dic[i].bit_sum(a-1)
      else:
        z = dic[i].bit_sum(b)
      if z>0:
        ans += 1
    print(ans)

Solution (Python):
import math

class segtree:
    def __init__(self,size):
        n = 1
        while n < size:
            n *= 2
        self.node = [0]*(2*n-1)
        self.begin = n

    def update(self,dex,value):
        dex += self.begin-1
        self.node[dex] = value
        while dex > 0:
            dex = (dex-1)//2
            self.node[dex] = self.node[dex*2+1] | self.node[dex*2+2]

    def segment(self,l,r):
        l += self.begin-1
        r += self.begin-1
        ans = 0
        while l <= r:
            if l==0:
                ans = self.node[0]
                break
            if l%2 == 0:
                ans |= self.node[l]
            l//=2
            if r%2 == 1:
                ans |= self.node[r]
            r = r//2 -1
        return ans

    def view(self):
        return  self.node

N = int(input())
seg = segtree(N)
S = input()
for i in range(N):
    seg.update(i,2**(ord(S[i])-ord("a")))
Q = int(input())
anses = []
for i in range(Q):
    a,b,c = input().split()
    if a=="1":
        seg.update(int(b)-1,2**(ord(c)-ord("a")))
    elif a=="2":
        ans = seg.segment(int(b)-1,int(c)-1)
        count = 0
        while ans:
            if ans & 1:
                count += 1
            ans >>= 1
        anses.append(count)
for i in anses:
    print(i)

Solution (Python):
class BIT1():
    """
    Binary Indexed Tree (1-indexed)
    """
    def __init__(self, n):
        self.n = n
        self.bit = [0] * (self.n + 1)
        self.data = [0] * (self.n + 1)

    def add(self, idx, x):
        
        
        self.data[idx] += x
        while idx <= self.n:
            self.bit[idx] += x
            idx += (idx & (-idx))

    def sum(self, idx):
        
        
        s = 0
        while idx:
            s += self.bit[idx]
            idx -= (idx & (-idx))
        return s


n = int(input())
s = [ord(si) - ord('a') for si in list(input())]
bit_list = [BIT1(n + 1) for _ in range(26)]
for i in range(n):
    bit_list[s[i]].add(i + 1, +1)

q = int(input())
for _ in range(q):
    k, a, b = input().split()
    k = int(k)
    a = int(a)
    if k == 1:
        b = ord(b) - ord('a')
        
        bit_list[s[a - 1]].add(a, -1)
        bit_list[b].add(a, +1)
        s[a - 1] = b
    else:
        
        b = int(b)
        a -= 1
        cnt = 0
        for bit_i in bit_list:
            if bit_i.sum(b) - bit_i.sum(a) > 0:
                cnt += 1
        print(cnt)

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

    numChar = 26
    
    ordA = ord('a')

    N = int(input())
    Ss = input()
    nos = [ord(S)-ordA for S in Ss]
    Q = int(input())

    def makeBIT(numEle):
        numPow2 = 2 ** (numEle-1).bit_length()
        datas = [[0]*(numPow2+1) for _ in range(numChar)]
        return datas, numPow2
    def addValue(no, iA, A):
        data = datas[no]
        iB = iA + 1
        while iB <= numPow2:
            data[iB] += A
            iB += iB & -iB
    def getSum(no, iA):
        data = datas[no]
        iB = iA + 1
        ans = 0
        while iB > 0:
            ans += data[iB]
            iB -= iB & -iB
        return ans
    def getRangeSum(no, iFr, iTo):
        return getSum(no, iTo) - getSum(no, iFr-1)


    datas, numPow2 = makeBIT(N)

    for i in range(N):
        no = nos[i]
        addValue(no, i, 1)

    anss = []
    for _ in range(Q):
        tp, v1, v2 = input().split()
        if tp == '1':
            pos = int(v1)-1
            no1 = nos[pos]
            no2 = ord(v2)-ordA
            addValue(no1, pos, -1)
            addValue(no2, pos, 1)
            nos[pos] = no2
        else:
            L, R = int(v1)-1, int(v2)-1
            ans = 0
            for no in range(numChar):
                if getRangeSum(no, L, R):
                    ans += 1
            anss.append(ans)

    print('\n'.join(map(str, anss)))


solve()

Solution (Python):
class BIT:
  ini = 0
  def __init__(s, num):
    s.N = 1
    while s.N <= num:
      s.N *= 2
    s.T = [s.ini] * s.N
  def set(s, L):
    for i in range(len(L)):
      s.update(i, L[i])
  def update(s, x, n):
    k = x + 1
    s.T[k - 1] += n
    k += k & -k
    while k <= s.N:
      s.T[k - 1] += n
      k += k & -k
  def getV(s, x):
    if x <= 0: return 0
    ans = s.T[x - 1]
    x -= x & -x
    while x != 0:
      ans += s.T[x - 1]
      x -= x & -x
    return ans

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

B = []
R = {}

def add(i, s):
  global cnt
  if s not in R:
    b = BIT(N)
    b.update(i, 1)
    R[s] = cnt
    cnt += 1
    B.append(b)
  else:
    t = R[s]
    B[t].update(i, 1)

def minus(i, s):
  global cnt
  t = R[s]
  B[t].update(i, -1)

cnt = 0
for i in range(N):
  s = S[i]
  add(i, s)

for i in range(Q):
  q = Query[i]
  q[0] = int(q[0])
  q[1] = int(q[1])
  if q[0] == 1:
    n = q[1] - 1
    s = S[n]
    add(n, q[2])
    minus(n, s)
    S[n] = q[2]
  else:
    ans = 0
    q[2] = int(q[2])
    x, y = q[1] - 1, q[2]
    for i in range(cnt): 
      if B[i].getV(x) != B[i].getV(y):
        ans += 1
    print(ans)

Solution (Python):
import math


def _hasParents(i):
    return i > 1


def _isLeftChild(i):
    return i % 2 == 0


def _isRightChild(i):
    return i % 2 == 1


def _parentNode(i):
    return i // 2


def _leftChild(i):
    return 2 * i


def _rightChild(i):
    return 2 * i + 1


def _leftSibling(i):
    return i - 1


def _rightSibling(i):
    return i + 1


def _nextPowerOfTwo(n):
    ret = 1
    while ret < n:
        ret *= 2
    return ret


def ancestors(i):
    while _hasParents(i):
        i = _parentNode(i)
        yield i


"""
class Config(NamedTuple, Generic[T, A]):
    mconvert: Callable[[T], A]
    mappend: Callable[[A, A], A]
    mempty: Callable[[], A]
"""
from collections import namedtuple

Config = namedtuple("Config", ["mconvert", "mappend", "mempty"])


class SegmentTree:
    def __init__(self, arr, mconvert, mappend, mempty, minCapacity=1):
        def wrappedMconvert(x):
            if x is not None:
                return mconvert(x)
            else:
                return mempty()

        def wrappedMappend(x, y):
            xEmpty = x == mempty()
            if xEmpty:
                return y
            yEmpty = y == mempty()
            if yEmpty:
                return x
            if xEmpty and yEmpty:
                return mempty()
            return mappend(x, y)

        self.config = Config(
            mconvert=wrappedMconvert, mappend=wrappedMappend, mempty=mempty
        )

        
        self.MAX_SIZE = _nextPowerOfTwo(max(len(arr), minCapacity))
        self.values = [None] * self.MAX_SIZE
        self.accumulations = [self.config.mempty()] * (2 * self.MAX_SIZE)
        self.numValues = 0

        
        self.values[: len(arr)] = arr
        self.numValues = len(arr)
        
        self.accumulations[self.MAX_SIZE : self.MAX_SIZE + len(arr)] = map(
            self.config.mconvert, arr
        )
        
        for parent in range(self.MAX_SIZE - 1, -1, -1):
            self.accumulations[parent] = self.config.mappend(
                self.accumulations[_leftChild(parent)],
                self.accumulations[_rightChild(parent)],
            )

    def query(self, i, j):
        
        if not (0 <= i <= j <= self.numValues):
            raise IndexError
        if i == j:
            return self.config.mempty()
        leftTotal = self.config.mempty()
        rightTotal = self.config.mempty()
        l = self.MAX_SIZE + i
        r = self.MAX_SIZE + j - 1  
        while l <= r:
            if _isRightChild(l):
                leftTotal = self.config.mappend(leftTotal, self.accumulations[l])
                l = _rightSibling(l)
            l = _parentNode(l)

            if _isLeftChild(r):
                rightTotal = self.config.mappend(self.accumulations[r], rightTotal)
                r = _leftSibling(r)
            r = _parentNode(r)
        return self.config.mappend(leftTotal, rightTotal)

    def append(self, x):
        assert self.numValues + 1 <= self.MAX_SIZE
        self.numValues += 1
        self.__setitem__(self.numValues - 1, x)

    def pop(self, i=None):
        if i is not None:
            raise NotImplementedError
        if not self.numValues:
            raise IndexError
        ret = self.__getitem__(self.numValues - 1)
        self.__delitem__(self.numValues - 1)
        return ret

    def insert(self, i, x):
        raise NotImplementedError


    def __getitem__(self, index):
        if isinstance(index, slice):
            raise NotImplementedError
        if not 0 <= index < self.numValues:
            raise IndexError
        ret = self.values[index]
        assert ret is not None
        return ret


    def __setitem__(self, i, x):
        if isinstance(i, slice):
            raise NotImplementedError
        
        if not 0 <= i < self.numValues:
            raise IndexError
        index = self.MAX_SIZE + i
        self.values[i] = x
        self.accumulations[index] = self.config.mconvert(x)
        for parent in ancestors(index):
            self.accumulations[parent] = self.config.mappend(
                self.accumulations[_leftChild(parent)],
                self.accumulations[_rightChild(parent)],
            )
            parent = _parentNode(parent)


    def __delitem__(self, i):
        if isinstance(i, slice):
            raise NotImplementedError
        if not 0 <= i < self.numValues:
            raise IndexError
        index = self.MAX_SIZE + i
        self.values[i] = None
        self.accumulations[index] = self.config.mempty()
        for parent in ancestors(index):
            self.accumulations[parent] = self.config.mappend(
                self.accumulations[_leftChild(parent)],
                self.accumulations[_rightChild(parent)],
            )
        self.numValues -= 1

    def __len__(self):
        return self.numValues


def charToBitmask(c):
    return 1 << (ord(c) - ord("a"))


def popcount(n):
    
    return bin(n).count("1")


N, = list(map(int, input().split()))
S = [charToBitmask(c) for c in input().rstrip()]
Q, = list(map(int, input().split()))
queries = []
for i in range(Q):
    queries.append(input().split())


segTree = SegmentTree(S, lambda x: x, lambda mask1, mask2: mask1 | mask2, lambda: 0)
out = []
for query in queries:
    if query[0] == "1":
        _, i, c = query
        i = int(i) - 1
        segTree[i] = charToBitmask(c)
    elif query[0] == "2":
        _, l, r = query
        l = int(l) - 1
        r = int(r) - 1
        mask = segTree.query(l, r + 1)

        out.append(str(popcount(mask)))
print("\n".join(out))

Solution (Python):
class SegmentTree():
    def __init__(self,arr,func=min,ie=2**63):
        self.n = 2**(len(arr)-1).bit_length()
        self.ie = ie
        self.func = func
        self.tree = [ie for _ in range(2*self.n)]
        for i in range(len(arr)):
            self.tree[self.n+i-1] = arr[i]
        for i in range(self.n-1)[::-1]:
            self.tree[i] = func(self.tree[2*i+1],self.tree[2*i+2])

    def set(self,index,x):
        index += self.n-1
        tree = self.tree
        func = self.func
        tree[index] = x
        while index:
            index = (index-1)//2
            tree[index] = func(tree[2*index+1],tree[2*index+2])

    def query(self,left,right):
        ie = self.ie
        tree = self.tree
        func = self.func
        if right <= left:
            return ie
        left += self.n-1
        right += self.n-2
        tmp_l = self.ie
        tmp_r = self.ie
        while right-left>1:
            if left & 1 == 0:
                tmp_l = func(tmp_l,tree[left])
            if right & 1 == 1:
                tmp_r = func(tree[right],tmp_r)
                right -= 1
            left = left//2
            right = (right-1)//2
        if left == right:
            tmp_l = func(tmp_l,tree[left])
        else:
            tmp_l = func(func(tmp_l,tree[left]),tree[right])
        return func(tmp_l,tmp_r)

import sys
input = sys.stdin.readline

N = int(input())
S = input()
Q = int(input())

A = []
for i in range(N):
    A.append(set([ord(S[i])-97]))

def func(x,y):
    return x|y
ie = set()

st = SegmentTree(A,func,ie)

ans = []

for _ in range(Q):
    q,x,y = input().split()
    q = int(q)
    if q == 1:
        st.set(int(x)-1,set([ord(y)-97]))
    else:
        ans.append(len(st.query(int(x)-1,int(y))))

print('\n'.join(map(str,ans)))

Solution (Python):
import sys
input = sys.stdin.readline
N = int(input())
S = list(input())[: -1]
Q = int(input())

class BIT:
  def __init__(self, n):
    self.n = n
    self.data = [0] * (n + 1)
    self.el = [0] * (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)

fwks = [BIT(N + 1) for _ in range(26)]
a = ord("a")
for i in range(N):
  j = ord(S[i]) - a
  
  fwks[j].add(i + 1, 1)
for _ in range(Q):
  q, x, y = input().split()
  q = int(q)
  if q == 1:
    x = int(x)
    for i in range(26):
      if fwks[i].get(x): fwks[i].add(x, -1)
    fwks[ord(y) - a].add(x, 1)
  else:
    x = int(x)
    y = int(y)
    res = 0
    
    for i in range(26):
      res += fwks[i].get(x - 1, y) > 0
    print(res)

Solution (Python):
n = int(input())
s = input()
q = int(input())
C = [0]*n
for i, k in enumerate(s):
  C[i] = 1<<(ord(k)-ord("a"))





def segfunc(a,b):
  return a | b

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] = 1<<x
    while k:
        k = (k-1)//2
        seg[k] = segfunc(seg[k*2+1],seg[k*2+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 = 0


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

init(C)
for _ in range(q):
  t, a, b = input().split()
  if t == "1":
    w = ord(b) - ord("a")
    update(int(a)-1, w)
  else:
    ans = query(int(a)-1, int(b))
    print(bin(ans).count("1"))

Solution (Python):
class BinaryIndexedTree():
    def __init__(self, N):
        self.N = N
        self.arr = [0] * (N+1)

    def query(self, i):
        ret = 0
        i += 1
        while i:
            ret += self.arr[i]
            lsb = i & (-i)
            i -= lsb
        return ret

    def add(self, i, v):
        i += 1
        while i < self.N+1:
            lsb = i & (-i)
            self.arr[i] += v
            i += lsb

    def search(self, x):
        lo = -1
        hi = self.N
        while lo < hi:
            mid = (lo+hi)//2
            if self.query(mid) < x:
                lo = mid + 1
            else:
                hi = mid
        return lo


def c2i(c):
    return ord(c) - ord('a')


def main():
    N = int(input())
    S = list(input())
    bits = [BinaryIndexedTree(N) for _ in range(26)]
    for i, c in enumerate(S):
        bits[c2i(c)].add(i, 1)
    Q = int(input())
    for _ in range(Q):
        t, x, y = input().split()
        if t == "1":
            i = int(x) - 1
            bits[c2i(S[i])].add(i, -1)
            bits[c2i(y)].add(i, 1)
            S[i] = y
        else:
            l, r = int(x), int(y)
            ans = 0
            for i in range(26):
                cs = bits[i].query(r-1)
                if l-2 >= 0:
                    cs -= bits[i].query(l-2)
                if cs >= 1:
                    ans += 1
            print(ans)


if __name__ == "__main__":
    main()

Solution (Python):
import itertools, operator
N = int(input())
S = [ord(s) - 97 for s in input()]
Q = int(input())
Query = [input().split() for _ in range(Q)]
cntraw = [[0] * (N + 1) for _ in range(26)]
for i, v in enumerate(S):
    cntraw[v][i + 1] = 1


class SegmentTree():
    def __init__(self, array, f, ti):
        """
        Parameters
        ----------
        array : list
            to construct segment tree from
        f : func
            binary operation of the monoid
        ti : 
            identity element of the monoid
        """
        self.f = f
        self.ti = ti
        self.n = n = 2**(len(array).bit_length())
        self.dat = dat = [ti] * n + array + [ti] * (n - len(array))
        for i in range(n - 1, 0, -1):  
            dat[i] = f(dat[i << 1], dat[i << 1 | 1])

    def update(self, p, v):  
        f, n, dat = self.f, self.n, self.dat
        p += n
        dat[p] = v
        while p > 1:
            p >>= 1
            dat[p] = f(dat[p << 1], dat[p << 1 | 1])

    def query(self, l, r):  
        f, ti, n, dat = self.f, self.ti, self.n, self.dat
        res = ti
        l += n
        r += n
        while l < r:
            if l & 1:
                res = f(res, dat[l])
                l += 1
            if r & 1:
                r -= 1
                res = f(dat[r], res)
            l >>= 1
            r >>= 1
        return res


sts = [SegmentTree(cntraw[i], f=operator.add, ti=0) for i in range(26)]
for query in Query:
    if query[0] == '1':
        i, c = query[1:]
        i = int(i)
        for st in sts:
            st.update(i, 0)
        sts[ord(c) - 97].update(i, 1)
    else:
        l, r = [int(_) for _ in query[1:]]
        r += 1
        print(sum(st.query(l, r) > 0 for st in sts))

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


class BIT:
    def __init__(self, size):
        self.bit = [0]*(size+1)
        self.size = size

    def sum(self, i):
        i += 1
        s = 0
        while i > 0:
            s += self.bit[i]
            i -= i & -i
        return s

    def add(self, i, x):
        i += 1
        while i <= self.size:
            self.bit[i] += x
            i += i & -i


N = int(input())
S = list(input().rstrip())
bits = [BIT(N) for _ in range(26)]
for i in range(N):
    bits[ord(S[i])-ord('a')].add(i, 1)
Q = int(input())
for _ in range(Q):
    t, x, y = input().split()
    if t == '1':
        i = int(x) - 1
        c = y
        bits[ord(S[i])-ord('a')].add(i, -1)
        bits[ord(c)-ord('a')].add(i, 1)
        S[i] = c
    else:
        l = int(x) - 1
        r = int(y) - 1
        ans = 0
        for i in range(26):
            cnt = bits[i].sum(r) - (bits[i].sum(l-1) if l > 0 else 0)
            if cnt > 0:
                ans += 1
        print(ans)

Solution (Python):
def examA():
    N = I()
    ans = N//2 + N%2
    print(ans)
    return

def examB():
    A = [LI()for _ in range(3)]
    N = I()
    B = [I()for _ in range(N)]
    grid = [[False]*3 for _ in range(3)]
    ans = "No"
    for b in B:
        for i in range(3):
            for j in range(3):
                if A[i][j]==b:
                    grid[i][j] = True
    for i in range(3):
        flag = True
        for j in range(3):
            if not grid[i][j]:
                flag = False
        if flag:
            ans = "Yes"
    for i in range(3):
        flag = True
        for j in range(3):
            if not grid[j][i]:
                flag = False
        if flag:
            ans = "Yes"
    flag = True
    for i in range(3):
        if not grid[i][i]:
            flag = False
    if flag:
        ans = "Yes"
    flag = True
    for i in range(3):
        if not grid[i][2-i]:
            flag = False
    if flag:
        ans = "Yes"
    print(ans)
    return

def examC():
    N, M = LI()
    S = [LI()for _ in range(M)]
    ans = [-1]*N
    for s,c in S:
        s -= 1
        if ans[s]!=-1:
            if ans[s]!=c:
                print(-1)
                return
        ans[s] = c
    A = ""
    if ans[0]==0 and N>=2:
        print(-1)
        return
    elif ans[0]==-1 and N>=2:
        ans[0] = 1
    for i in ans:
        if i==-1:
            A += str(0)
        else:
            A += str(i)
    print(A)
    return

def examD():
    class UnionFind():
        def __init__(self, n):
            self.parent = [-1 for _ in range(n)]
            

        def find(self, x):
            
            if self.parent[x] < 0:
                return x
            else:
                self.parent[x] = self.find(self.parent[x])
                return self.parent[x]

        def unite(self, x, y):
            
            x, y = self.find(x), self.find(y)
            if x == y:
                return False
            else:
                if self.size(x) < self.size(y):
                    x, y = y, x
                self.parent[x] += self.parent[y]
                self.parent[y] = x

        def same(self, x, y):
            
            return self.find(x) == self.find(y)

        def size(self, x):
            
            x = self.find(x)
            return -self.parent[x]

        def is_root(self, x):
            
            return self.parent[x] < 0

        def roots(self):
            
            return [i for i, x in enumerate(self.parent) if x < 0]

        def members(self, x):
            
            root = self.find(x)
            return [i for i in range(self.n) if self.find(i) == root]

        def group_count(self):
            
            return len(self.roots())

        def all_group_members(self):
            
            return {r: self.members(r) for r in self.roots()}

    N, M, K = LI()
    uf = UnionFind(N)
    B = [0]*N
    for _ in range(M):
        a, b = LI()
        B[a-1] += 1
        B[b-1] += 1
        uf.unite(a-1,b-1)
    block = []
    for _ in range(K):
        c, d = LI()
        c -= 1
        d -= 1
        if uf.same(c,d):
            B[c] += 1
            B[d] += 1
    ans = [0]*N
    check = [-1]*N
    for i in range(N):
        root = uf.find(i)
        if check[root]==-1:
            size = uf.size(root)
            check[root] = size
        else:
            size = check[root]
        ans[i] += size-1
        ans[i] -= B[i]
        if ans[i]<0:
            ans[i] = 0
    
    print(" ".join(map(str,ans)))
    return

def examE():
    
    class segment_():
        def __init__(self, A, n, segfunc, ide_ele=0):
            
            self.ide_ele = ide_ele
            
            self.num = 1 << (n - 1).bit_length()
            self.seg = [self.ide_ele] * 2 * self.num
            self.segfunc = segfunc
            
            for i in range(n):
                self.seg[i + self.num] = A[i]
                
            for i in range(self.num - 1, 0, -1):
                self.seg[i] = self.segfunc(self.seg[2 * i], self.seg[2 * i + 1])

        def update(self, k, r):
            k += self.num
            self.seg[k] = r
            while k:
                k >>= 1
                self.seg[k] = self.segfunc(self.seg[k * 2], self.seg[k * 2 + 1])

        
        def update1(self, k):
            k += self.num
            self.seg[k] += 1
            while k:
                k >>= 1
                self.seg[k] = self.segfunc(self.seg[k * 2], self.seg[k * 2 + 1])

        def updateneg1(self, k):
            k += self.num
            self.seg[k] -= 1
            while k:
                k >>= 1
                self.seg[k] = self.segfunc(self.seg[k * 2], self.seg[k * 2 + 1])

        def query(self, p, q):
            
            if q < p:
                return self.ide_ele
            p += self.num;
            q += self.num
            res = self.ide_ele
            while p < q:
                if p & 1 == 1:
                    res = self.segfunc(res, self.seg[p])
                    p += 1
                if q & 1 == 1:
                    q -= 1
                    res = self.segfunc(res, self.seg[q])
                p >>= 1;
                q >>= 1
            return res

    def popcnt0(n):
        c = 0
        for i in range(27):
            c += (n >> i) & 1
        return c
    N = I()
    S = SI()
    Q = I()
    a = ord('a')
    A = [0] * (N+1)
    for i in range(N):
        A[i] = 1<<(ord(S[i]) - a)
    Seg_sum = segment_(A, N+1, lambda a, b: a | b)
    ans = []
    for _ in range(Q):
        q = LSI()
        if q[0]=="1":
            cur = 1<<(ord(q[2])-a)
            Seg_sum.update(int(q[1])-1,cur)
        else:
            cur = Seg_sum.query(int(q[1])-1,int(q[2]))
            ans.append(popcnt0(cur))
            
    
    for v in ans:
        print(v)
    return

def examF():
    ans = 0
    print(ans)
    return

import sys,copy,bisect,itertools,heapq,math,random
from heapq import heappop,heappush,heapify
from collections import Counter,defaultdict,deque
def I(): return int(sys.stdin.readline())
def LI(): return list(map(int,sys.stdin.readline().split()))
def LSI(): return list(map(str,sys.stdin.readline().split()))
def LS(): return sys.stdin.readline().split()
def SI(): return sys.stdin.readline().strip()
global mod,mod2,inf,alphabet,_ep
mod = 10**9 + 7
mod2 = 998244353
inf = 10**18
_ep = 10**(-12)
alphabet = [chr(ord('a') + i) for i in range(26)]

if __name__ == '__main__':
    examE()

"""

"""