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
read = sys.stdin.readline


def read_a_int():
    return int(read())


class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木 (下書き)
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  
        self.tree = [self.ide] * (2 * self.num - 1)  
        for i, l in enumerate(ls):  
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num - 1
        r += self.num - 2  
        res = self.ide
        while r - l > 1:  
            if l & 1 == 0:
                res = self.func(res, self.tree[l])
            if r & 1 == 1:
                res = self.func(res, self.tree[r])
                r -= 1
            l = l // 2  
            r = (r - 1) // 2  
        if l == r:
            res = self.func(res, self.tree[l])
        else:
            res = self.func(res, self.tree[l])
            res = self.func(res, self.tree[r])
        return res


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


def moji_to_bit(a):
    return 1 << (ord(a) - ord('a'))


def bit_to_sum(n):
    return sum([(n >> i) & 1 for i in range(n.bit_length())])


N = read_a_int()
S = read()[:-1]
S_bit = [moji_to_bit(s) for s in S]


st = SegmentTree(S_bit, segfunc, 0)

Q = read_a_int()
for q in range(Q):
    com, a, b = read().split()
    if int(com) == 1:
        i, c = int(a) - 1, b
        st.update(i, moji_to_bit(c))
    else:
        l, r = int(a) - 1, int(b)
        print(bit_to_sum(st.query(l, r)))

Solution (Python):
class SegmentTree:
	def __init__(self, n, *, init = None, data = None, merge = None):
		if init != None and data != None:
			raise Error("init and data cannot be specified at a time")
		if init == None and data == None:
			raise Error("one of init or data must be specified")
		self.n = n
		data_table = []
		if data:
			data_table.append((1, data))
		else:
			data_table.append((1, tuple(init(i, i + 1) for i in range(n))))
		
		w = 2
		if merge == None:
			while w <= n:
				data_table.append((w, tuple(init(i, i + w) for i in range(0, ((n - 1) // w + 1) * w, w))))
				w *= 2
		else:
			last_data = data_table[0][1]
			while w <= n:
				if len(last_data) % 2 == 0:
					new_data = tuple(merge(last_data[i * 2], last_data[i * 2 + 1]) for i in range(0, (n - 1) // w + 1))
				else:
					new_data = tuple(merge(last_data[i * 2], last_data[i * 2 + 1]) for i in range(0, (n - 1) // w)) + (merge(last_data[-1], None), )
				data_table.append((w, new_data))
				last_data = new_data
				w *= 2
		self.data_table = data_table
		
	def data_at(self, i):
		for w, data_list in self.data_table:
			yield data_list[i // w]
	
	def data_range(self, s, e = None):
		if e == None:
			e = s
			s = 0
		if s == 0:
			for w, data_list in reversed(self.data_table):
				if e % (w * 2) >= w:
					yield data_list[e // w - 1]
		elif s < e:
			for w, data_list in self.data_table:
				w2 = w * 2
				m = s % w2
				new_s = s + w2 - m
				if new_s > e:
					break
				if m != 0:
					yield data_list[s // w]
					s = new_s
			if s == e:
				return
			for w, data_list in reversed(self.data_table):
				new_s = s + w
				if new_s <= e:
					yield data_list[s // w]
					s = new_s
			
			return
			for w, data_list in self.data_table:

				w2 = w * 2
				m = s % w2
				if m != 0:
					yield data_list[s // w]
					s += w2 - m
					if s == e:
						break
				m = e % w2
				if m != 0:
					yield data_list[e // w - 1]
					e -= m
					if s == e:
						break
	
	def check(self, merge):
		last_data = self.data_table[0][1]
		for w, data in self.data_table[1:]:
			if len(last_data) % 2 == 0:
				new_data = tuple(merge(last_data[i * 2], last_data[i * 2 + 1]) for i in range(0, (self.n - 1) // w + 1))
			else:
				new_data = tuple(merge(last_data[i * 2], last_data[i * 2 + 1]) for i in range(0, (self.n - 1) // w)) + (last_data[-1], )
			if new_data != data:
				print(new_data)
				print(data)
				raise "hoge"
			last_data = new_data
			w *= 2
	
	def output(self, func):
		for w, data_list in self.data_table:

			pass


A = ord("a")
N = int(input())
S = list(map(lambda c: ord(c) - A, input().strip()))
Q = int(input())

def count(s, e):
	counts = [0] * 26
	for i in range(s, min(N, e)):
		counts[S[i]] += 1
	return counts

def merge(count1, count2):
	result = list(count1)
	if count2 != None:
		for i in range(26):
			result[i] += count2[i]
	return result

st = SegmentTree(N, init = count, merge = merge)


def set2str(s):
	return "".join(chr(A + j) if s[j] > 0 else "" for j in range(26))

for _ in range(Q):
	t, i, q = input().split()
	
	if t == "1":
		i = int(i) - 1
		q = ord(q) - A
		s = S[i]
		for data in st.data_at(i):
			data[s] -= 1
			data[q] += 1
		S[i] = q
		

		
	else:
		l = int(i) - 1
		r = int(q)
		result = [0] * 26
		for data in st.data_range(l, r):
			for i in range(26):
				result[i] += data[i]
		
		count = 0
		for i in range(26):
			if result[i] > 0:
				count += 1

		
		print(count)

Solution (Python):












class Segtree:
    

    

    
    
    

    

    def __init__(s,l,unit,oper):
        s.unit = unit
        s.oper = oper
        s.n = 1
        while s.n<l:
            s.n *= 2
        s.ary = [s.unit for i in range(2*s.n-1)]

    def get(s,i):
        return s.ary[i+s.n-1]

    def set(s,i,v):
        k = i+s.n-1
        s.ary[k] = v
        while k>0:
            k = (k-1)//2
            s.ary[k] = s.oper( \
                        s.ary[2*k+1], s.ary[2*k+2])

    def setary(s,a):
        for i,v in enumerate(a):
            s.ary[i+s.n-1] = v
        for k in range(s.n-2,-1,-1):
            s.ary[k] = s.oper( \
                        s.ary[2*k+1], s.ary[2*k+2])

    def query(s,x,y):
        return s.querycore(x,y,0,0,s.n)

    
    

    def querycore(s,x,y,k,l,r):
        if r<=x or y<=l:
            return s.unit
        if x<=l and r<=y:
            return s.ary[k]
        vl = s.querycore(x,y,2*k+1,l,(l+r)//2)
        vr = s.querycore(x,y,2*k+2,(l+r)//2,r)
        return s.oper(vl, vr)




inn = lambda : int(input())
inl   = lambda: list(map(int, input().split()))
inm   = lambda:      map(int, input().split())
ins = lambda : input().strip()

n = inn()
sgt = Segtree(n, 0, lambda x,y: x|y)
ss = ins()
s = []
for i in range(n):
    sgt.set(i, 1<<(ord(ss[i])-ord('a')))






q = inn()
for qq in range(q):
    x,y,z = input().split()
    
    if x == '1':
        i = int(y)-1
        c = z
        sgt.set(i, 1<<(ord(c)-ord('a')))
    else:
        l = int(y)
        r = int(z)
        sm = 0
        v = sgt.query(l-1,r)
        for i in range(26):
            if (v>>i)%2==1:
                sm += 1
        print(sm)

Solution (Python):
def main():
    import sys
    buf = sys.stdin.buffer

    class SegmentTree:
        def __init__(self, target, no_effect):
            target_size = len(target)
            leaves_size = 1
            while leaves_size < target_size:
                leaves_size *= 2
            self.tree_size = leaves_size * 2 - 1
            self.to_leaf = self.tree_size//2
            self.tree = [no_effect] * self.tree_size
            self.no_effect = no_effect
            self.initialize_tree(target)

        @classmethod
        def initialize_func(cls, value):
            return 1 << (ord(value) - 97)

        @classmethod
        def merge_func(cls, a, b):
            return a | b

        def merge_child_data(self, node):
            child1 = node * 2 + 1
            child2 = node * 2 + 2
            return self.merge_func(self.tree[child1], self.tree[child2])

        def initialize_tree(self, target):
            initial_leaf = self.tree_size // 2
            leaves = range(initial_leaf, initial_leaf+len(target))
            for value, leaf in zip(target, leaves):
                self.tree[leaf] = self.initialize_func(value)

            for parent in range(initial_leaf-1, -1, -1):
                self.tree[parent] = self.merge_child_data(parent)

        def update(self, new_value, index):
            leaf = self.tree_size//2 + index
            new_data = self.initialize_func(new_value)
            if self.tree[leaf] == new_data:
                return
            self.tree[leaf] = new_data

            parent = (leaf-1) // 2
            while parent >= 0:
                new_data = self.merge_child_data(parent)
                if self.tree[parent] == new_data:
                    break
                self.tree[parent] = new_data
                parent = (parent-1) // 2

        def resolve_query(self, _from, to):
            result = self.no_effect
            left, right = _from + self.to_leaf, to + self.to_leaf
            while left <= right:
                result = self.merge_func(result, self.tree[left])
                result = self.merge_func(result, self.tree[right])
                left //= 2
                right = right//2 - 1

            return bin(result).count('1')

    n, S, _, *queries = buf.read().split()
    S = S.decode()
    seg_tree = SegmentTree(target=S, no_effect=0)

    for type, a, b in zip(*[iter(queries)]*3):
        if type == b'1':
            index, new = int(a)-1, b
            seg_tree.update(new, index)

        elif type == b'2':
            _from, to = int(a)-1, int(b)-1
            print(seg_tree.resolve_query(_from, to))


if __name__ == '__main__':
    main()

Solution (Python):
def main():
    import sys
    buf = sys.stdin.buffer

    class SegmentTree:
        def __init__(self, target, no_effect):
            target_size = len(target)
            leaves_size = 1
            while leaves_size < target_size:
                leaves_size *= 2
            self.tree_size = leaves_size * 2 - 1
            self.tree = [no_effect] * self.tree_size
            self.no_effect = no_effect
            self.initialize_tree(target)

        @classmethod
        def initialize_func(cls, value):
            return 1 << (ord(value) - ord('a'))

        @classmethod
        def merge_func(cls, a, b):
            return a | b

        def merge_child_data(self, node):
            child1 = node * 2 + 1
            child2 = node * 2 + 2
            merged = self.merge_func(self.tree[child1], self.tree[child2])
            return merged

        def initialize_tree(self, target):
            initial_leaf = self.tree_size // 2
            leaves = range(initial_leaf, initial_leaf+len(target))
            for value, leaf in zip(target, leaves):
                self.tree[leaf] = self.initialize_func(value)

            for parent in range(initial_leaf-1, -1, -1):
                self.tree[parent] = self.merge_child_data(parent)

        def update(self, new_value, index):
            leaf = self.tree_size//2 + index
            new_data = self.initialize_func(new_value)
            if self.tree[leaf] == new_data:
                return
            self.tree[leaf] = new_data

            parent = (leaf-1) // 2
            while parent >= 0:
                new_data = self.merge_child_data(parent)
                if self.tree[parent] == new_data:
                    break
                self.tree[parent] = new_data
                parent = (parent-1) // 2

        def resolve_query(self, _from, to):
            result = self.no_effect
            left, right = _from + self.tree_size//2, to + self.tree_size//2
            while left <= right:
                result = self.merge_func(result, self.tree[left])
                result = self.merge_func(result, self.tree[right])
                left //= 2
                right = right//2 - 1

            return bin(result).count('1')

    n, S, _, *queries = buf.read().split()
    S = S.decode()
    seg_tree = SegmentTree(target=S, no_effect=0)

    for type, a, b in zip(*[iter(queries)]*3):
        if type == b'1':
            index, new = int(a)-1, b
            seg_tree.update(new, index)

        elif type == b'2':
            _from, to = int(a)-1, int(b)-1
            print(seg_tree.resolve_query(_from, to))


if __name__ == '__main__':
    main()

Solution (Python):
def main():
    import sys
    buf = sys.stdin.buffer

    class SegmentTree:
        def __init__(self, target, no_effect):
            target_size = len(target)
            leaves_size = 1
            while leaves_size < target_size:
                leaves_size *= 2
            self.tree_size = leaves_size * 2 - 1
            self.tree = [no_effect] * self.tree_size
            self.no_effect = no_effect
            self.initialize_tree(target)

        @classmethod
        def initialize_func(cls, value):
            return 1 << (ord(value) - ord('a'))

        @classmethod
        def merge_func(cls, a, b):
            return a | b

        def merge_child_data(self, node):
            child1 = node * 2 + 1
            child2 = node * 2 + 2
            merged = self.merge_func(self.tree[child1], self.tree[child2])
            return merged

        def initialize_tree(self, target):
            initial_leaf = self.tree_size // 2
            leaves = range(initial_leaf, initial_leaf+len(target))
            for value, leaf in zip(target, leaves):
                self.tree[leaf] = self.initialize_func(value)

            for parent in range(initial_leaf-1, -1, -1):
                self.tree[parent] = self.merge_child_data(parent)

        def update(self, new_value, index):
            leaf = self.tree_size//2 + index
            new_data = self.initialize_func(new_value)
            if self.tree[leaf] == new_data:
                return
            self.tree[leaf] = new_data

            parent = (leaf-1) // 2
            while parent >= 0:
                new_data = self.merge_child_data(parent)
                if self.tree[parent] == new_data:
                    break
                self.tree[parent] = new_data
                parent = (parent-1) // 2

        def resolve_query(self, _from, to):
            result = self.no_effect
            left, right = _from + self.tree_size//2, to + self.tree_size//2
            while left <= right:
                result = self.merge_func(result, self.tree[left])
                result = self.merge_func(result, self.tree[right])
                left //= 2
                right = right//2 - 1

            return bin(result).count('1')

    n, S, _, *queries = buf.read().split()
    S = S.decode()
    seg_tree = SegmentTree(target=S, no_effect=0)

    for type, a, b in zip(*[iter(queries)]*3):
        if type == b'1':
            index, new = int(a)-1, b
            seg_tree.update(new, index)

        elif type == b'2':
            _from, to = int(a)-1, int(b)-1
            print(seg_tree.resolve_query(_from, to))


if __name__ == '__main__':
    main()

Solution (Python):
import math
n = int(input())
s = input()
ss = [[(1 << ord(c) - ord('a')) for c in s]]
while len(ss[-1]) > 1:
    r = []
    for i in range(0, len(ss[-1]), 2):
        if i + 1 < len(ss[-1]):
            r.append(ss[-1][i] | ss[-1][i + 1])
        else:
            r.append(ss[-1][i])
    ss.append(r)


def update(j, v):
    ss[0][j] = v
    for k in range(1, len(ss)):
        j = j // 2
        
        if 2 * j + 1 < len(ss[k - 1]):
            ss[k][j] = ss[k - 1][2 * j] | ss[k - 1][2 * j + 1]
        else:
            ss[k][j] = ss[k - 1][2 * j]
    

def all_or(i, j, k):
    
    if i == j:
        return 0
    while True:
        if k == 0:
            return ss[0][i]
        ik, jk = (i >> k), (j >> k)
        
        if ik != jk:
            break
        k -= 1
    r = 0
    if i == ik << k:
        r = ss[k][ik]
    else:
        r = all_or(i, (ik + 1) << k, k - 1)
    for l in range(ik + 1, jk):
        r |= ss[k][l]
    r |= all_or(jk << k, j, k - 1)
    return r

def popcount(v):
    r = 0
    while v != 0:
        v = (v & (v - 1))
        r += 1
    return r

q = int(input())

for i in range(q):
    cs = [x for x in input().split()]
    cs[0], cs[1] = int(cs[0]), int(cs[1]) - 1
    if cs[0] == 1:
        
        update(cs[1], (1 << (ord(cs[2]) - ord('a'))))
    else:
        
        
        
        
        print(popcount(all_or(cs[1], int(cs[2]), len(ss) - 1)))

Solution (Python):

import sys
sys.setrecursionlimit(10**9)
INF=10**18
MOD=10**9+7
def input(): return sys.stdin.readline().rstrip()

def main():
    class SegmentTree:
        def __init__(self,n,ide_ele,segfunc):
            self.ide_ele=ide_ele
            self.segfunc=segfunc
            self.num=2**(n-1).bit_length()
            self.dat=[ide_ele]*2*self.num
        
        def init(self,iter):
            for i in range(n):
                self.dat[i+self.num-1]=iter[i]
            for i in range(self.num-2,-1,-1):
                self.dat[i]=self.segfunc(self.dat[2*i+1],self.dat[2*i+2])
        
        def update(self,k,x):
            k+=self.num-1
            self.dat[k]=x
            while k:
                k=(k-1)//2
                self.dat[k]=self.segfunc(self.dat[k*2+1],self.dat[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.dat[p])
                if q&1==1:
                    res=self.segfunc(res,self.dat[q])
                    q-=1
                p=p//2
                q=(q-1)//2
            if p==q:
                res=self.segfunc(res,self.dat[p])
            else:
                res=self.segfunc(self.segfunc(res,self.dat[p]),self.dat[q])
            return res
    
    N=int(input())
    S=list(input())
    Q=int(input())
    seg=[SegmentTree(N,0,lambda x,y:x+y) for _ in range(26)]
    
    S2=[0]*N
    
    for i in range(N):
        S2[i]=ord(S[i])-ord('a')
    
    for i,x in enumerate(S2):
        p=seg[x].query(i,i+1)
        seg[x].update(i,p+1)
    
    for _ in range(Q):
        a,b,c=input().split()
        if a=='1':
            b=int(b)-1
            c=ord(c)-ord('a')
            p=seg[c].query(b,b+1)
            seg[c].update(b,p+1)
            q=seg[S2[b]].query(b,b+1)
            seg[S2[b]].update(b,q-1)
            S2[b]=c
        else:
            b=int(b)-1
            c=int(c)-1
            ans=0
            for i in range(26):
                ans+=bool(seg[i].query(b,c+1))
            print(ans)

if __name__ == '__main__':
    main()

Solution (Python):
N = int(input())
S = input()

seg = [0]*(2*N-1)

def update(k, x):
    k += N-1
    seg[k] = 2**x
    while k:
        k = (k-1)//2
        seg[k] = seg[2*k+1] | seg[2*k+2]
        
def query(p, q):
    p += N-1
    q += N-2
    res = 0
    while q-p > 1:
        if p&1 == 0:
            res = res | seg[p]
        if q&1 == 1:
            res = res | seg[q]
            q -= 1
        p //= 2
        q = (q-1)//2
    if p == q:
        res |= seg[q]
    else:
        res |= seg[p] | seg[q]
    return bin(res).count("1")

def f(s):
    return ord(s) - ord("a") + 1

for i in range(N):
    update(i, f(S[i]))
    
Q = int(input())
for _ in range(Q):
    a,b,c = map(str, input().split())
    if a == "1":
        update(int(b)-1, f(c))
    else:
        print(query(int(b)-1, int(c)))

Solution (Python):




class SegTree:
    def __init__(self,n):
        self.size=1
        while(n>self.size):
            self.size<<=1
        self.nod=[0 for i in range(self.size*2-1)]
    def update(self,k,a):
        k+=self.size-1
        self.nod[k]+=a
        while(k>0):
            k=(k-1)>>1
            self.nod[k]|=a
    def dedate(self, k, a):
        k += self.size-1
        self.nod[k] -= a
        while(k>0):
            k=(k-1)>>1
            self.nod[k] = self.nod[(k<<1)|1]|self.nod[(k+1)<<1]
    def query(self,a,b,k,l,r):
        if(r<=a or b<=l):
            return 0
        if(a<=l and r<=b):
            return self.nod[k]
        else:
            return self.query(a,b,(k<<1)|1,l,(l+r)>>1)|self.query(a,b,(k+1)<<1,(l+r)>>1,r)

def pop_c(x):
    ret = 0
    while x:
        ret += x&1
        x>>=1
    return ret

n = int(input())
t = input()
q = int(input())
EE = ord('a')
st = SegTree(n)
s = [t[i] for i in range(n)]

def adding(x, c):
    global st
    st.dedate(x, 1<<(ord(s[x])-EE))
    st.update(x, 1<<(ord(c)-EE))
    s[x] = c

def query(l, r):
    now = st.query(l, r+1, 0, 0, st.size)
    return pop_c(now)

for i in range(n):
    st.update(i, 1<<(ord(s[i])-EE))
ans = []
for i in range(q):
    x,l,r = map(str,input().split())
    if x=='1':
        adding(int(l)-1, r)
    else:
        ans.append(query(int(l)-1, int(r)-1))
for i in range(len(ans)):
    print(ans[i])

Solution (Python):
from collections import Counter,defaultdict,deque
from bisect import bisect_left
import sys,math,itertools,pprint,fractions
sys.setrecursionlimit(10**8)
mod = 10**9+7
INF = float('inf')
def inp(): return int(sys.stdin.readline())
def inpl(): return list(map(int, sys.stdin.readline().split()))

n = inp()
s = list(input())
q = inp()
Qs = [input().split() for i in range(q)]
upd = []
acc = [[0] * 26 for i in range(n+1)]
for i,t in enumerate(s):
    tmp = ord(t) - ord('a')
    
    for j in range(26):
        if j == tmp:
            acc[i+1][j] = acc[i][j] + 1
            continue
        acc[i+1][j] = acc[i][j]

for i,t in enumerate(Qs):
    a,b,c = t
    b = int(b)
    if a == '1':
        upd.append([b,ord(s[b-1])-ord('a'),ord(c)-ord('a')])
        s[b-1] = c
    else:
        c = int(c)
        cnt = 0
        now = [0] * 26
        for j in range(26):
            now[j] = acc[c][j] - acc[b-1][j]
        for j,k in enumerate(upd):
            if b <= k[0] <= c:
                now[k[1]] -= 1
                now[k[2]] += 1
        for j in range(26):
            if now[j] > 0: cnt += 1
        print(cnt)

Solution (Python):
def main():
    N = int(input())
    S = input()
    tree = SegmentTree(S, f=lambda x,y:x|y, converter=lambda c: 1 << (ord(c)-ord('a')))
    Q = int(input())
    update = tree.update
    query = tree.query
    for _ in range(Q):
        t, a, b = input().split()
        if t == '1': update(int(a)-1, b)
        else: print(bin(query(int(a)-1, int(b))).count('1'))    

class SegmentTree:
    def __init__(self, initial_values, f=max, zero_factory=int, converter=lambda x:x):
        self.__f, self.__z, self.__c = f, zero_factory, converter
        self.__n = 1 << ((len(initial_values) - 1).bit_length())
        self.__dat = [zero_factory() for _ in range(2 * self.__n)]
        zi = self.__get_leaf(0)
        for i, v in enumerate(initial_values): self.__dat[zi + i] = converter(v)
        for i in range(zi-1, -1, -1): self.__dat[i] = f(*self.__get_children(i))

    def update(self, index, value):
        i, v = self.__get_leaf(index), self.__c(value)
        if self.__dat[i] == v: return
        self.__dat[i] = v
        while i:
            i = self.__get_parent(i)
            self.__dat[i] = self.__f(*self.__get_children(i))

    def query(self, from_inclusive, to_exclusive):
        ans = self.__z()
        if to_exclusive <= from_inclusive: return ans
        l, r = self.__get_leaf(from_inclusive), self.__get_leaf(to_exclusive) - 1
        while r - l > 1:
            if self.__is_right(l): ans = self.__f(ans, self.__dat[l])
            if self.__is_left(r): ans, r = self.__f(ans, self.__dat[r]), r-1
            l, r = l//2, self.__get_parent(r)
        ans = self.__f(ans, self.__dat[l])
        if l != r: ans = self.__f(ans, self.__dat[r])
        return ans

    def __get_leaf(self, i): return self.__n + i - 1
    def __get_parent(self, i): return (i-1)//2
    def __get_children(self, i): return (self.__dat[2*i+1], self.__dat[2*i+2])
    def __is_left(self, i): return i&1 == 1
    def __is_right(self, i): return i&1 == 0

if __name__ == '__main__':
    main()

Solution (Python):
class segmentTreeOR():
    initValue = 0
    dat = []
    lenTreeList = -1
    depthTreeList = 0
    lenOriginalList = -1

    def __init__(self):
        pass

    def load(self, l):
        
        self.lenOriginalList = len(l)
        self.lenTreeList = 2 ** (len(l) - 1).bit_length()  
        self.depthTreeList = (len(l) - 1).bit_length()  
        self.dat = [self.initValue] * (self.lenTreeList * 2)
        
        for i in range(len(l)):
            self.dat[self.lenTreeList - 1 + i] = l[i]
        self.build()

    def build(self):
        for i in range(self.lenTreeList - 2, -1, -1):
            self.dat[i] = self.dat[2 * i + 1] | self.dat[2 * i + 2]

    def setValue(self, i, a):
        """
        set a to list[i]
        """
        
        nodeId = (self.lenTreeList - 1) + i
        
        self.dat[nodeId] = a
        while nodeId != 0:
            nodeId = (nodeId - 1) // 2
            
            self.dat[nodeId] = self.dat[nodeId * 2 + 1] | self.dat[nodeId * 2 + 2]

    def querySub(self, a, b, nodeId, l, r):
        """
        [a,b) 区間の親クエリに対するノードnodeへ[l, r)の探索をデリゲート
        区間については、dataの添え字は0,1,2,3,4としたときに、
        [0,3)なら0,1,2の結果を返す
        """
        
        if (r <= a or b <= l):
            return self.initValue
        if a <= l and r <= b:
            return self.dat[nodeId]
        resLeft = self.querySub(a, b, 2 * nodeId + 1, l, (l + r) // 2)
        resRight = self.querySub(a, b, 2 * nodeId + 2, (l + r) // 2, r)
        return resLeft | resRight

    def query(self, a, b):
        return self.querySub(a, b, 0, 0, self.lenTreeList)


def count_ones_by_bin(num):
    bin_num = bin(num)[2:]
    count = 0
    for i in bin_num:
        count += int(i)
    return count

n = int(input())
s = input()
sl = list(s)
sl = list(map(lambda x: ord(x) - ord("a"), sl))

l = list(map(lambda x: 1 << x, sl))

st = segmentTreeOR()
st.load(l)

q = int(input())
for _ in range(q):
    ty, x, y = input().split()
    x = int(x)
    if ty == "1":
        nind = ord(y[0]) - ord("a") 
        st.setValue(x-1, 1 << nind)
    elif ty == "2":
        x = int(x) - 1
        y = int(y)
        res = 0
        cnt = st.query(x, y)
        print(count_ones_by_bin(cnt))
    else:
        print("error")

Solution (Python):
def main():
  import sys
  n,s,_,*t=sys.stdin.buffer.read().split()
  n=int(n)
  d=[0]*n+[1<<c-97for c in s]
  for i in range(n-1,0,-1):d[i]=d[i+i]|d[i-~i]
  for q,a,b in zip(*[iter(t)]*3):
    i,s=int(a)+n-1,0
    if q<b'2':
      d[i]=1<<b[0]-97
      while i>1:
        i//=2
        d[i]=d[i+i]|d[i-~i]
      continue
    j=int(b)+n
    while i<j:
      if i&1:
        s|=d[i]
        i+=1
      if j&1:
        j-=1
        s|=d[j]
      i//=2
      j//=2
    print(bin(s).count('1'))
main()

Solution (Python):
def main():
  import sys
  n,s,_,*t=sys.stdin.buffer.read().split()
  n=int(n)
  d=[0]*n+[1<<c-97for c in s]
  for i in range(n-1,0,-1):d[i]=d[i+i]|d[i-~i]
  for q,a,b in zip(*[iter(t)]*3):
    i,s=int(a)+n-1,0
    if q<b'2':
      d[i]=1<<ord(b)-97
      while i>1:
        i//=2
        d[i]=d[i+i]|d[i-~i]
      continue
    j=int(b)+n
    while i<j:
      if i&1:
        s|=d[i]
        i+=1
      if j&1:
        j-=1
        s|=d[j]
      i//=2
      j//=2
    print(bin(s).count('1'))
main()

Solution (Python):
def main():
  import sys
  n,s,_,*t=sys.stdin.buffer.read().split()
  n=int(n)
  d=[0]*n+[1<<c-97for c in s]
  for i in range(n-1,0,-1):d[i]=d[i+i]|d[i-~i]
  for q,a,b in zip(*[iter(t)]*3):
    i,s=int(a)+n-1,0
    if q<b'2':
      d[i]=1<<ord(b)-97
      while i>1:
        i//=2
        d[i]=d[i+i]|d[i-~i]
      continue
    j=int(b)+n
    while i<j:
      if i&1:
        s|=d[i]
        i+=1
      if j&1:
        j-=1
        s|=d[j]
      i//=2
      j//=2
    print(bin(s).count('1'))
main()

Solution (Python):
n,s,_,*t=open(0).read().split()
n=int(n)
d=[0]*n+[1<<ord(c)-97for c in s]
for i in range(n-1,0,-1):d[i]=d[i+i]|d[i-~i]
for q,a,b in zip(*[iter(t)]*3):
  i,s=int(a)+n-1,0
  if'2'>q:
    d[i]=1<<ord(b)-97
    while i>1:
      i//=2
      d[i]=d[i+i]|d[i-~i]
    continue
  j=int(b)+n
  while i<j:
    if i&1:
      s|=d[i]
      i+=1
    if j&1:
      j-=1
      s|=d[j]
    i//=2
    j//=2
  print(bin(s).count('1'))

Solution (Python):
n,s,_,*t=open(0).read().split()
n=int(n)
d=[0]*n+[1<<ord(c)-97for c in s]
for i in range(n-1,0,-1):d[i]=d[i+i]|d[i-~i]
for q,a,b in zip(*[iter(t)]*3):
  i,s=int(a)+n-1,0
  if'2'>q:
    d[i]=1<<ord(b)-97
    while i>1:
      i//=2
      d[i]=d[i+i]|d[i-~i]
    continue
  j=int(b)+n
  while i<j:
    if i&1:
      s|=d[i]
      i+=1
    if j&1:
      j-=1
      s|=d[j]
    i//=2
    j//=2
  print(bin(s).count('1'))

Solution (Python):
n=int(input())+1
d=[0]*n*2
def update(i,x):
  i+=n
  d[i]=x
  while i//2:
    i//=2
    d[i]=d[i+i]|d[i-~i]
def query(l,r):
  l+=n
  r+=n
  s=0
  while l<r:
    if l&1:
      s|=d[l]
      l+=1
    if r&1:
      r-=1
      s|=d[r]
    l//=2
    r//=2
  return bin(s).count('1')
for i,c in enumerate(input(),n):d[i]=1<<ord(c)-97
for i in range(n-1,0,-1):d[i]=d[i+i]|d[i-~i]
for _ in range(int(input())):
  q,a,b=input().split()
  if q>'1':print(query(int(a)-1,int(b)))
  else:update(int(a)-1,1<<ord(b)-97)