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):
class BIT:
    def __init__(self, n):
        """
            data : BIT木データ
            el : 元配列
        """
        self.n = n
        self.data = [0]*(n+1)
        self.el = [0]*(n+1)
    
    """A1 ~ Aiまでの累積和"""
    def Sum(self, i):
        s = 0
        while i > 0:
            s += self.data[i]
            i -= i & (-i)   
        return s
    
    """Ai += x"""
    def Add(self, i, x):
        self.el[i] += x
        while i <= self.n:
            self.data[i] += x
            i += i & -i
    
    """Ai ~ Ajまでの累積和"""
    def Get(self, i, j=None):
        if j is None:
            return self.el[i]
        return self.Sum(j) - self.Sum(i)

def ctoi(c):
    return ord(c) - 97

n = int(input())
s = list(input())
q = int(input())

bits = [BIT(n) for _ in range(26)]
ans = []
for i in range(n):
    bits[ctoi(s[i])].Add(i+1, 1)
for _ in range(q):
    line = list(input().split())
    if line[0] == '1':
        idx = int(line[1])
        bits[ctoi(s[idx-1])].Add(idx, -1)
        s[idx-1] = line[2]
        bits[ctoi(line[2])].Add(idx, 1) 
    else:
        l,r = int(line[1]), int(line[2])
        cnt = 0
        for i in range(26):
            if bits[i].Get(l-1,r)!=0:
                cnt += 1
        ans.append(cnt)
for a in ans:
    print(a)

Solution (Python):
class BIT:
    def __init__(self, n):
        self.node = [ 0 for _ in range(n+1) ]

    def add(self, idx, w):
        i = idx
        while i < len(self.node) - 1:
            self.node[i] += w
            i |= (i + 1)

    def sum_(self, idx):
        ret, i = 0, idx-1
        while i >= 0:
            ret += self.node[i]
            i = (i & (i + 1)) - 1
        return ret

    def sum(self, l, r):
        return self.sum_(r) - self.sum_(l)


n = int(input())
s = list(input())
q = int(input())

tree = [ BIT(n) for _ in range(26) ]
for i in range(n):
    tree_id = ord(s[i]) - ord("a")
    tree[tree_id].add(i, 1)

for _ in range(q):
    query = input().split()
    com = int(query[0])
    if com == 1:
        idx, new_char = int(query[1]), query[2]
        idx -= 1
        old_char = s[idx]
        new_id = ord(new_char) - ord("a")
        old_id = ord(old_char) - ord("a")

        tree[old_id].add(idx, -1)
        tree[new_id].add(idx, 1)
        s[idx] = new_char

    if com == 2:
        l, r = int(query[1]), int(query[2])
        ret = 0
        for c in range(26):
            if tree[c].sum(l-1, r) > 0:
                ret += 1
        print(ret)

Solution (Python):
def ctoi(x):
    return ord(x)-ord("a")
n = int(input())
s = list(input())
q = int(input())
bit = [[0]*(n+1) for _ in range(26)]

def update(pos,a,x):
    while pos<=n:
        bit[a][pos] += x
        pos += pos&(-pos)

def query(pos):
    ret=[0]*26
    for i in range(26):
        tmp=0
        p=pos
        while p>0:
            tmp+=bit[i][p]
            p-=p&(-p)
        ret[i]=tmp
    return ret

for i in range(n):
    update(i+1,ctoi(s[i]),1)

for _ in range(q):
    flag,a,b = input().split()
    flag=int(flag)
    a=int(a)
    if flag==1:
        if s[a-1]==b:
            continue
        else:
            update(a,ctoi(s[a-1]),-1)
            update(a,ctoi(b),1)
            s[a-1]=b
    else:
        b=int(b)
        c1 = query(b)
        c2 = query(a-1)
        ans = 0
        for i in range(26):
            if c1[i]-c2[i]>0:
                ans += 1
        print(ans)

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

    def sum(self, i):
        i += 1
        res = 0
        while (i > 0):
            res += self.bit[i]
            i -= i & -i
        return res
    
    def add(self, i, target):
        i += 1
        while i <= self.num:
            self.bit[i] += target
            i += i & -i
    
    
    def query(self, l, r):
        return self.sum(r-1) - self.sum(l-1)

def main():
    N = int(input())
    S = list(input())
    Q = int(input())
    anss = []
    bits = [BinaryIndexedTree(N) for i in range(26)]

    for index, c in enumerate(S):
        bits[ord(c) - ord('a')].add(index, 1)
    
    for _ in range(Q):
        query = input().split()
        if query[0] == "1":
            index = int(query[1]) - 1
            target = query[2]
            if S[index] == target:
                continue
            else:
                bits[ord(S[index])-ord('a')].add(index, -1)
                S[index] = target
                bits[ord(target)-ord('a')].add(index, 1)
        else:
            l, r = map(int, query[1:])
            l-= 1; r-= 1
            ans = 0
            for i in range(26):
                if bits[i].query(l, r+1) > 0:
                    ans += 1
            anss.append(ans)
    print(*anss, sep="\n")

if __name__ == "__main__":
    main()

Solution (Python):


class SegmentTree():
    def __init__(self, num, segfunc, ide_ele):
        length = 2 ** (num-1).bit_length()
        self.n = num
        self.func = segfunc
        self.seg = [ide_ele] * 2 * length
        self.ide_ele = ide_ele
    
    def update(self, index, target):
        index += self.n - 1
        self.seg[index] = target
        while (index > 0):
            index = (index - 1) // 2
            self.seg[index] = self.func(self.seg[index*2 + 1], self.seg[index*2 + 2])
    
    
    def quary(self, l, r):
        l += self.n - 1
        r += self.n - 1
        res = self.ide_ele
        while l < r :
            if l & 1 == 0:
                res = self.func(res, self.seg[l])
            if r & 1 == 0:
                res = self.func(res, self.seg[r-1])
            l = l // 2
            r = (r-1) // 2
        return res

def main():
    N = int(input())
    S = list(input())
    Q = int(input())
    anss = []
    ide_ele = 10 ** 9
    segs = [SegmentTree(N, min, ide_ele) for i in range(26)]
    for index, c in enumerate(S):
        segs[ord(c) - ord('a')].update(index, index)
    
    for _ in range(Q):
        query = input().split()
        if query[0] == "1":
            index = int(query[1]) - 1
            target = query[2]
            if S[index] == target:
                continue
            else:
                segs[ord(S[index])-ord('a')].update(index, ide_ele)
                S[index] = target
                segs[ord(target)-ord('a')].update(index, index)
        else:
            l, r = map(int, query[1:])
            l-= 1; r-= 1
            ans = 0
            for i in range(26):
                if segs[i].quary(l, r+1) <= r:
                    ans += 1
            anss.append(ans)
    print(*anss, sep="\n")

if __name__ == "__main__":
    main()

Solution (Python):
import bisect

N=int(input())
S=list(str(input()))

def ci(x):
  return "abcdefghijklmnopqrstuvwxyz".find(x)

d=[[] for _ in range(26)]
for i,s in enumerate(S):
  d[ci(s)].append(i)

for i in range(int(input())):
  t,x,y=input().split()
  if t=="1":
    x=int(x)-1
    if S[x]!=y:
      l=bisect.bisect_left(d[ci(S[x])],x)
      d[ci(S[x])].pop(l)
      bisect.insort(d[ci(y)],x)
      S[x]=y
  else:
    x,y=int(x)-1,int(y)-1
    c=0
    for j in range(26):
      l=bisect.bisect_left(d[j],x)
      if l<len(d[j]) and d[j][l] <= y:
        c += 1
    print(c)

Solution (Python):
import bisect
from collections import defaultdict

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

alpha_dic = defaultdict(list)

for i, s in enumerate(S):
    alpha_dic[s].append(i)

for _ in range(Q):
    l, m, n = input().split()

    if l == '1':
        m = int(m) - 1
        c = S[m]

        if c == n:
            continue
        else:
            i = bisect.bisect_left(alpha_dic[c], m)
            del alpha_dic[c][i]

            bisect.insort_left(alpha_dic[n], m)
            S[m] = n
    else:
        m, n = int(m) - 1, int(n) - 1

        cnt = 0
        for _, val in alpha_dic.items():
            if not val:
                continue

            left_idx = bisect.bisect_left(val, m)
            right_idx = bisect.bisect_left(val, n)
            l = len(val)

            if left_idx > right_idx or (left_idx == right_idx and left_idx == l) or (left_idx == right_idx and val[left_idx] != m and val[right_idx] != n):
                continue

            cnt += 1

        print(cnt)

Solution (Python):
class SegTree:

    def __init__(self, N, S):
        self.N = 1
        while self.N < N:
            self.N *= 2
        self.tree = [0 for i in range(2 * self.N - 1)]
        for i in range(len(S)):
            self.tree[self.N - 1 + i] = 1 << (ord(S[i]) - ord('a'))
        for i in range(self.N - 2, -1, -1):
            self.tree[i] = self.tree[i * 2 + 1] | self.tree[i * 2 + 2]

    def update(self, index, char):
        i = self.N - 1 + index
        self.tree[i] = 1 << (ord(char) - ord('a'))

        while i > 0:
            i = (i - 1) // 2
            self.tree[i] = self.tree[i * 2 + 1] | self.tree[i * 2 + 2]

    def get(self, a, b):
        return self.query(a, b, 0, 0, self.N)

    def query(self, a, b, k, l, r):
        if r <= a or b <= l:
            return 0
        elif a <= l and r <= b:
            return self.tree[k]
        else:
            left = self.query(a, b, 2 * k + 1, l, (l + r) // 2)
            right = self.query(a, b, 2 * k + 2, (l + r) // 2, r)
            return left | right


def solve():

    N = int(input())
    S = list(input())
    tree = SegTree(N, S)

    Q = int(input())
    for _ in range(Q):
        t_q, in_1, in_2 = input().split()
        if t_q == '1':
            i_q = int(in_1)
            c_q = in_2
            tree.update(i_q-1, c_q)
        elif t_q == '2':
            l_q = int(in_1)
            r_q = int(in_2)
            print(bin(tree.get(l_q-1, r_q)).count('1'))


solve()

Solution (Python):
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)


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.propagate(
                    self.nodes[i*2+1], self.nodes[i*2+2])

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

    def __setitem__(self, i, x):  
        i += self.N0 - 1
        self.nodes[i].val = x
        while i > 0:
            i = (i-1)//2
            self.nodes[i] = self.propagate(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):  
        retnode = Node(0, 0)
        L += self.N0
        R += self.N0
        while L < R:
            if R & 1:
                R -= 1
                retnode = self.propagate(retnode, self.nodes[R-1])
            if L & 1:
                retnode = self.propagate(retnode, self.nodes[L-1])
                L += 1
            L >>= 1
            R >>= 1
        return retnode

    def propagate(self, node_x, node_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())

Solution (Python):
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)


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):  
        return self.nodes[key+self.N0-1].val

    def __setitem__(self, 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):  
        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):  
        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())

Solution (Python):
import bisect

n = int(input())
s = list(input())
q = int(input())

pos = [[] for i in range(26)]
alp = "abcdefghijklmnopqrstuvwxyz"
atoi = {}
for i in range(26):
    atoi[alp[i]] = i
for i in range(n):
    pos[atoi[s[i]]].append(i)

for i in range(q):
    a, b, c = input().split()
    if a == "1":
        b = int(b)-1
        if c == s[b]:
            continue
        index = bisect.bisect_left(pos[atoi[s[b]]], b)
        del pos[atoi[s[b]]][index]
        bisect.insort_left(pos[atoi[c]], b)
        s[b] = c
    else:
        l, r = int(b)-1, int(c)
        ans = 0
        for i in range(26):
            cnt = bisect.bisect_left(pos[i], r) - bisect.bisect_left(pos[i], l)
            if cnt > 0:
                ans += 1
        print(ans)

Solution (Python):
import sys

def input(): return sys.stdin.readline().rstrip()
sys.setrecursionlimit(10 ** 7)

import bisect
from string import ascii_lowercase
d = dict()
for i, c in enumerate(ascii_lowercase):
    d[c] = i

N = int(input())
S = list(input())
lst = [[] for _ in range(26)]
for i in range(N):
    lst[d[S[i]]].append(i)

Q = int(input())
for q in range(Q):
    a, b, c = input().split()
    if a=='1':
        i = int(b)-1
        if c == S[i]:   
            continue
        idx = bisect.bisect_left(lst[d[S[i]]],i)
        del lst[d[S[i]]][idx]
        bisect.insort_left(lst[d[c]],i)
        S[i] = c
    else:
        l = int(b)-1
        r = int(c)
        ans = 0
        for i in range(26):
            cnt = bisect.bisect_left(lst[i],r) - bisect.bisect_left(lst[i],l)
            if cnt:
                ans += 1
        print(ans)

Solution (Python):

import sys

N=input()
S=["None"]+list(raw_input())
Q=input()
query=[ sys.stdin.readline().split() for _ in range(Q) ]


bit=[ [ 0 for _ in range(N+1) ] for _ in range(27) ]  

def add(idx,a,w):
    while a<=N:
        bit[idx][a]+=w
        a+=a&-a

def sum(idx,a):
    ret=0
    while 0<a:
        ret+=bit[idx][a]
        a-=a&-a
    return ret

for i,x in enumerate(S):
    if i==0: continue
    add(ord(x)-96,i,1)  


for q1,q2,q3 in query:
    q1=int(q1)
    q2=int(q2)
    if q1==1:
        before_q3=S[q2] 
        S[q2]=q3        
        q3=ord(q3)-96                   
        before_q3=ord(before_q3)-96     
        add(q3,q2,1)                    
        add(before_q3,q2,-1)    
    elif q1==2:
        q3=int(q3)
        cnt=0
        for i in range(1,27):
            if 0<sum(i,q3)-sum(i,q2-1):
                cnt+=1
        print cnt

Solution (Python):





N = int(input())
s = input()


N0 = 1
while N0<=N:
    N0*=2
INF = 0
data = [0]*(2*N0)

def update(k, x):
    k += N0-1
    data[k] = 1<<x
    while k >= 0:
        k = (k - 1) // 2
        data[k] =data[2*k+1]|data[2*k+2]

def query(l, r):
    L = l + N0; R = r + N0
    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = s|data[R-1]

        if L & 1:
            s = s|data[L-1]
            L += 1
        L >>= 1; R >>= 1
    return s

for i in range(N):
    update(i,ord(s[i])-ord("a"))
q = int(input())

for j in range(q):
    t,l,r = input().split( )
    if t=="1":
        update(int(l)-1,ord(r)-ord("a"))
        
    else:
        bit = bin(query(int(l)-1,int(r)))[2:]
        ans = 0
        for i in bit:
            ans += int(i)
        print(ans)

Solution (Python):

import sys

N=input()
S=["None"]+list(raw_input())
Q=input()
query=[ sys.stdin.readline().split() for _ in range(Q) ]


bit=[ [ 0 for _ in range(N+1) ] for _ in range(27) ]  

def add(idx,a,w):
    while a<=N:
        bit[idx][a]+=w
        a+=a&-a

def sum(idx,a):
    ret=0
    while 0<a:
        ret+=bit[idx][a]
        a-=a&-a
    return ret

for i,x in enumerate(S):
    if i==0: continue
    add(ord(x)-96,i,1)  


for q1,q2,q3 in query:
    q1=int(q1)
    q2=int(q2)
    if q1==1:
        before_q3=S[q2] 
        S[q2]=q3        
        q3=ord(q3)-96                   
        before_q3=ord(before_q3)-96     
        add(q3,q2,1)                    
        add(before_q3,q2,-1)    
    elif q1==2:
        q3=int(q3)
        cnt=0
        for i in range(1,27):
            if 0<sum(i,q3)-sum(i,q2-1):
                cnt+=1
        print cnt

Solution (Python):
import sys
input=sys.stdin.readline
N=int(input())
S=input()
Q=int(input())
D={}
A=["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
for i in range(26):
    D[A[i]]=i
n=1
while n<N:
    n*=2

seg=[0 for i in range(n*2)]


for i in range(N):
    seg[n-1+i]=1<<D[S[i]]
    k=n-1+i
    while k>0:
        k=(k-1)//2
        seg[k]=(seg[k*2+1]|seg[k*2+2])



def update(a,b):
    a+=n-1
    seg[a]=1<<D[b]
    while a>0:
        a=(a-1)//2
        seg[a]=(seg[a*2+1]|seg[a*2+2])







def query(A,B,K,L,R):
    if K>=len(seg):
        return 0
    if R<=A or B<=L:
        return 0
    elif A<=L and R<=B:
        return seg[K]
    else:
        vl=query(A,B,K*2+1,L,(L+R)//2)
        vr=query(A,B,K*2+2,(L+R)//2,R)
        
        return vl|vr





for i in range(Q):
    x,y,z=list(input().split())
    if x=="1":
        update(int(y)-1,z)
    else:
        print(list(bin(query(int(y)-1,int(z),0,0,n))).count("1"))

Solution (Python):
class SegmentTree(object):  
    def __init__(self, size, S):
        self.len = 1 << size.bit_length()

        self.array = [0] * (2 * self.len)
        for i, s in enumerate(S):
            self.array[i + self.len] = 1 << (ord(s) - ord('a'))
        for i in range(self.len - 1, 0, -1):
            self.array[i] = self.array[i * 2] | self.array[i * 2 + 1]

    def query1(self, i, x):
        i += self.len
        self.array[i] = 1 << (ord(x) - ord('a'))
        i >>= 1
        while i > 0:
            self.array[i] = self.array[i * 2] | self.array[i * 2 + 1]
            i >>= 1

    def get(self, i):
        return self.array[i + self.len]

    def query(self, l, r, i, a, b):
        if l == a and r == b:
            return self.array[i]
        center = (a + b) // 2
        if center >= r:
            return self.query(l, r, i * 2, a, center)
        elif center <= l:
            return self.query(l, r, i * 2 + 1, center, b)
        else:
            return self.query(l, center, i * 2, a, center) | self.query(center, r, i * 2 + 1, center, b)

    def query2(self, l, r):
        ans = self.query(l - 1, r, 1, 0, self.len)
        print(bin(ans).count('1'))


N = int(input())
S = input()
tree = SegmentTree(N, S)
Q = int(input())

for _ in range(Q):
    a, b, c = map(str, input().split())
    if a == "1":
        b = int(b)
        tree.query1(b-1, c)
    else:
        b = int(b)
        c = int(c)
        tree.query2(b, c)

Solution (Python):


import sys

DEBUG = False


class SegmentTree:

    
    def __init__(self, n, merge_func, fillval=sys.maxsize):
        self.n = 1
        while self.n < n:
            self.n *= 2
        self.nodes = [fillval] * (self.n * 2 - 1 + 1)  
        self.merge_func = merge_func
        self.fillval = fillval
    
    def update(self, idx, val):
        idx += 1  

        nodes = self.nodes
        mergef = self.merge_func

        idx += self.n - 1
        nodes[idx] = val
        while idx > 1: 
            idx >>= 1  
            nodes[idx] = mergef(nodes[idx << 1], nodes[(idx << 1) + 1]) 
    
    def query(self, l, r):
        l += 1; r += 1  

        l += self.n - 1
        r += self.n - 1
        acc = self.fillval
        while l < r:
            if l & 1:
                acc = self.merge_func(acc, self.nodes[l])
                l += 1
            if r & 1:
                acc = self.merge_func(acc, self.nodes[r - 1])
                r -= 1
            l >>= 1
            r >>= 1
        return acc

def read(t = str):
    return t(sys.stdin.readline().rstrip())

def read_list(t = str, sep = " "):
    return [t(s) for s in sys.stdin.readline().rstrip().split(sep)]

def dprint(*args, **kwargs):
    if DEBUG:
        print(*args, **kwargs)
    return


def main():
    read()
    s = read()

    a_ord = ord("a")
    bit_offsets = {chr(c_ord): c_ord - a_ord for c_ord in range(ord("a"), ord("z") + 1)}

    apps = SegmentTree(len(s), lambda x, y: x | y, 0)
    i = 0
    for c in s:
        apps.update(i, 1 << bit_offsets[c])
        i += 1

    nr_q = read(int)
    for i in range(0, nr_q):
        q = read_list()
        if q[0] == "1":
            _, i, c = q  
            apps.update(int(i) - 1, 1 << bit_offsets[c])
        else:
            _, l, r = q  
            print(bin(apps.query(int(l) - 1, int(r) - 1 + 1)).count("1"))  


if __name__ == "__main__":
    main()

Solution (Python):
import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,copy,functools
import time,random

sys.setrecursionlimit(10**7)
inf = 10**20
eps = 1.0 / 10**10
mod = 10**9+7
mod2 = 998244353
dd = [(-1,0),(0,1),(1,0),(0,-1)]
ddn = [(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1)]

def LI(): return list(map(int, sys.stdin.readline().split()))
def LLI(): return [list(map(int, l.split())) for l in sys.stdin.readlines()]
def LI_(): return [int(x)-1 for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def LS(): return sys.stdin.readline().split()
def I(): return int(sys.stdin.readline())
def F(): return float(sys.stdin.readline())
def S(): return input()
def pf(s): return print(s, flush=True)
def pe(s): return print(str(s), file=sys.stderr)
def JA(a, sep): return sep.join(map(str, a))
def JAA(a, s, t): return s.join(t.join(map(str, b)) for b in a)


class Seg():
    def __init__(self, na, default, func):
        if isinstance(na, list):
            n = len(na)
        else:
            n = na
        i = 1
        while 2**i <= n:
            i += 1
        self.D = default
        self.H = i
        self.N = 2**i
        if isinstance(na, list):
            self.A = [default] * (self.N) + na + [default] * (self.N-n)
            for i in range(self.N-1,0,-1):
                self.A[i] = func(self.A[i*2], self.A[i*2+1])
        else:
            self.A = [default] * (self.N*2)
        self.F = func

    def find(self, i):
        return self.A[i + self.N]

    def update(self, i, x):
        i += self.N
        self.A[i] = x
        while i > 1:
            i = i // 2
            self.A[i] = self.merge(self.A[i*2], self.A[i*2+1])

    def merge(self, a, b):
        return self.F(a, b)

    def total(self):
        return self.A[1]

    def query(self, a, b):
        A = self.A
        l = a + self.N
        r = b + self.N
        res = self.D
        while l < r:
            if l % 2 == 1:
                res = self.merge(res, A[l])
                l += 1
            if r % 2 == 1:
                r -= 1
                res = self.merge(res, A[r])
            l >>= 1
            r >>= 1

        return res

def main():
    n = I()
    s = S()
    q = I()
    qa = [LS() for _ in range(q)]
    aa = [[0]*26]
    oa = ord('a')
    for c in s:
        t = [0] * 26
        t[ord(c) - oa] = 1
        aa.append(t)

    def f(a,b):
        return [a[i]+b[i] for i in range(26)]

    seg = Seg(aa,[0]*26,f)
    r = []
    for t,a,b in qa:
        if t == '1':
            u = [0] * 26
            u[ord(b) - oa] = 1
            seg.update(int(a),u)
        else:
            c = seg.query(0,int(a))
            d = seg.query(0,int(b)+1)
            r.append(len([1 for i in range(26) if c[i] != d[i]]))

    return JA(r, '\n')


print(main())

Solution (Python):
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)

Solution (Python):
from bisect import bisect_left,insort_left
n=int(input())
s=list(input())
lindex=[[] for _ in range(26)]
for i in range(n):
  lindex[ord(s[i])-97].append(i)
q=int(input())
for i in range(q):
  q1,q2,q3=input().split()
  if q1=='1':
    q2=int(q2)-1
    idx=bisect_left(lindex[ord(s[q2])-97],q2)
    if s[q2]!=q3:
      del lindex[ord(s[q2])-97][idx]
      insort_left(lindex[ord(q3)-97],q2)
      s[q2]=q3
  else:
    l=int(q2)-1
    r=int(q3)-1
    cnt=0
    for j in range(26):
      if len(lindex[j])==0:
        continue
      idx=bisect_left(lindex[j],l)
      if len(lindex[j])>idx and lindex[j][idx]<=r:
        cnt+=1
    print(cnt)

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

def resolve():

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

        def add(self, item, pos):
            index = pos
            while index < self.n+1:
                self.bit[index] += item
                index += index & (-index)

        def sum(self, pos):
            ret = 0
            index = pos
            while index > 0:
                ret += self.bit[index]
                index -= index & -index
            return ret

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

    pos_bit_list = [BinaryIndexedTree(len(S)) for _ in range(26)]

    for i, c in enumerate(S):
        pos_bit_list[ord(c)-ord('a')].add(1, i+1)

    for q in Query:
        if q[0] == '1':
            pos_bit_list[ord(S[int(q[1])-1])-ord('a')].add(-1, int(q[1]))
            pos_bit_list[ord(q[2])-ord('a')].add(1, int(q[1]))
            S[int(q[1])-1] = q[2]
        else:
            print(len([p for p in pos_bit_list if p.sum(int(q[2])) - p.sum(int(q[1])-1) > 0]))

if __name__ == '__main__':
    resolve()