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.



Sample input:
7
abcdbbd
6
2 3 6
1 5 z
2 1 1
1 4 a
1 7 d
2 1 7


Sample output:
3
1
5

Submission status: Accepted

Solution code:
from collections import defaultdict, deque, Counter
from heapq import heappush, heappop, heapify
import math
import bisect
import random
from itertools import permutations, accumulate, combinations, product
import sys
import string
from bisect import bisect_left, bisect_right
from math import factorial, ceil, floor
from operator import mul
from functools import reduce
import pprint
sys.setrecursionlimit(10 ** 9)


INF = 10 ** 20
def LI(): return list(map(int, sys.stdin.buffer.readline().split()))
def I(): return int(sys.stdin.buffer.readline())
def LS(): return sys.stdin.buffer.readline().rstrip().decode('utf-8').split()
def S(): return sys.stdin.buffer.readline().rstrip().decode('utf-8')
def IR(n): return [I() for i in range(n)]
def LIR(n): return [LI() for i in range(n)]
def SR(n): return [S() for i in range(n)]
def LSR(n): return [LS() for i in range(n)]
def SRL(n): return [list(S()) for i in range(n)]
def MSRL(n): return [[int(j) for j in list(S())] for i in range(n)]
mod = 1000000007


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

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

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

    def interval_sum(self, i, j): # i <= x < j の区間
        return self.sum(j - 1) - self.sum(i - 1) if i else self.sum(j - 1)

n = I()
s = list(S())
D = defaultdict(lambda:BIT(n))
for i in range(n):
    D[s[i]].add(i, 1)

q = I()
for j in range(q):
    qi, i, c = LS()
    if qi == '1':
        i = int(i) - 1
        D[s[i]].add(i, -1)
        D[c].add(i, 1)
        s[i] = c
    else:
        l, r = int(i) - 1, int(c)
        ret = 0
        for k in range(97, 123):
            if D[chr(k)].interval_sum(l, r):
                ret += 1
        print(ret)

Submission status: Accepted

Solution code:
# Binary Indexed Treeを各アルファベットについてもつ (それぞれN+1の空間を保持し、1-indexで考える)
N = int(input())
S = list(input())
BITS = [[0]*(N+1) for _ in range(26)]
# 初期化を行おうと思ったが、これ自体に関数が必要である
# 値の加算


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


# 1~idxまでの文字に各文字がどれだけ出現するか
def BIT_query(idx):
    res = [0]*26
    for i in range(26):
        p = idx
        tmp = 0
        while p > 0:
            tmp += BITS[i][p]
            p -= p & (-p)
        res[i] = tmp
    return res


def BIT_update(idx, alphabet, x):  # idx: int, alphabet: str, x: int
    while idx <= N:
        BITS[ctoi(alphabet)][idx] += x
        idx += idx&(-idx)


# 初期化を行う
for i in range(N):
    BIT_update(i+1, S[i], 1)

# クエリを受け取っていく
Q = int(input())
for _ in range(Q):
    type, a, b = map(str, input().split())
    if type == "1":  # 更新のクエリなら
        # このとき、aはindex, bは変更後の文字(str)である
        a = int(a)
        if S[a-1] == b:
            continue
        BIT_update(a, S[a-1], -1)  # 減らす処理
        BIT_update(a, b, 1)  # 増やす処理
        S[a-1] = b
    elif type == "2":  # 回答する必要があるクエリ
        # このとき、aは左端, bは右端
        a, b = int(a), int(b)
        cnt1 = BIT_query(a-1)
        cnt2 = BIT_query(b)
        ans = 0
        for i in range(26):
            if cnt2[i] > cnt1[i]:
                ans += 1
        print(ans)

Submission status: Accepted

Solution code:
from collections import defaultdict, deque, Counter
from heapq import heappush, heappop, heapify
import math
import bisect
import random
from itertools import permutations, accumulate, combinations, product
import sys
import string
from bisect import bisect_left, bisect_right
from math import factorial, ceil, floor
from operator import mul
from functools import reduce
import pprint
sys.setrecursionlimit(10 ** 9)


INF = 10 ** 20
def LI(): return list(map(int, sys.stdin.buffer.readline().split()))
def I(): return int(sys.stdin.buffer.readline())
def LS(): return sys.stdin.buffer.readline().rstrip().decode('utf-8').split()
def S(): return sys.stdin.buffer.readline().rstrip().decode('utf-8')
def IR(n): return [I() for i in range(n)]
def LIR(n): return [LI() for i in range(n)]
def SR(n): return [S() for i in range(n)]
def LSR(n): return [LS() for i in range(n)]
def SRL(n): return [list(S()) for i in range(n)]
def MSRL(n): return [[int(j) for j in list(S())] for i in range(n)]
mod = 1000000007


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

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

    def sum(self, i):
        if i < 0:
            return 0
        res = 0
        x = i + 1
        while x:
            res += self.bit[x - 1]
            x -= x & -x
        return res

    def interval_sum(self, i, j): # i <= x < j の区間
        return self.sum(j - 1) - self.sum(i - 1)


n = I()
s = list(S())
D = defaultdict(lambda:BIT(n))
for i in range(n):
    D[ord(s[i])].add(i, 1)

q = I()
for j in range(q):
    qi, i, c = LS()
    i = int(i) - 1
    if qi == '1':
        D[ord(s[i])].add(i, -1)
        D[ord(c)].add(i, 1)
        s[i] = c
    else:
        l, r = i, int(c)
        ret = 0
        for k in range(97, 123):
            if D[k].sum(r - 1) > D[k].sum(l - 1):
                ret += 1
        print(ret)

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline

def main():
    N = int(input())
    S = input().rstrip()
    tree = SegmentTree(initial_values=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().rstrip().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, n=None, f=max, zero_factory=int, converter=lambda x:x, initial_values=None):
        assert(n or initial_values)
        size = n if n else len(initial_values)
        self.__f, self.__z, self.__c = f, zero_factory, converter
        self.__n = 1 << ((size - 1).bit_length())
        self.__dat = [zero_factory() for _ in range(2 * self.__n)]
        if initial_values:
            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)
            v = self.__f(*self.__get_children(i))
            if self.__dat[i] == v: break
            self.__dat[i] = v

    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()

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline

def main():
    N = int(input())
    S = input().rstrip()
    tree = SegmentTree(initial_values=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().rstrip().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, n=None, f=max, zero_factory=int, converter=lambda x:x, initial_values=None):
        assert(n or initial_values)
        size = n if n else len(initial_values)
        self.__f, self.__z, self.__c = f, zero_factory, converter
        self.__n = 1 << ((size - 1).bit_length())
        self.__dat = [zero_factory() for _ in range(2 * self.__n)]
        if initial_values:
            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()

Submission status: Accepted

Solution code:
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

def main():
    N,S,Q,*q = read().split()
    S = S.decode()
    tree = SegmentTree(initial_values=S, f=lambda x,y:x|y, converter=lambda c: 1 << (ord(c)-ord('a')))
    update = tree.update
    query = tree.query
    for t, a, b in zip(*[iter(q)]*3):
        if t == b'1': update(int(a)-1, b)
        else: print(bin(query(int(a)-1, int(b))).count('1'))

class SegmentTree:
    def __init__(self, n=None, f=max, zero_factory=int, converter=lambda x:x, initial_values=None):
        assert(n or initial_values)
        size = n if n else len(initial_values)
        self.__f, self.__z, self.__c = f, zero_factory, converter
        self.__n = 1 << ((size - 1).bit_length())
        self.__dat = [zero_factory() for _ in range(2 * self.__n)]
        if initial_values:
            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()

Submission status: Accepted

Solution code:
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

def main():
    N,S,Q,*q = read().split()
    S = S.decode()
    tree = SegmentTree(initial_values=S, f=lambda x,y:x|y, converter=lambda c: 1 << (ord(c)-ord('a')))
    for t, a, b in zip(*[iter(q)]*3):
        if t == b'1': tree.update(int(a)-1, b)
        else: print(bin(tree.query(int(a)-1, int(b))).count('1'))

class SegmentTree:
    def __init__(self, n=None, f=max, zero_factory=int, converter=lambda x:x, initial_values=None):
        assert(n or initial_values)
        size = n if n else len(initial_values)
        self.__f, self.__z, self.__c = f, zero_factory, converter
        self.__n = 1 << ((size - 1).bit_length())
        self.__dat = [zero_factory() for _ in range(2 * self.__n)]
        if initial_values:
            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()

Submission status: Accepted

Solution code:
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
def main():
    N,S,Q,*q = read().decode().split()
    N = int(N)
    S = list(S)

    c = lambda x: ord(x) - ord('a')
    tree = [SegmentTree(N, lambda x,y:x|y) for _ in range(26)]
    for i, l in enumerate(S):
        tree[c(l)].update(i, 1)

    for t, a, b in zip(*[iter(q)]*3):
        if t == '1':
            a = int(a) - 1
            tree[c(S[a])].update(a, 0)
            tree[c(b)].update(a, 1)
            S[a] = b
        else:
            a, b = int(a)-1, int(b)-1
            ans = 0
            for i in range(26):
                t = tree[i].query(a, b+1)
                ans += 1 if t else 0
            print(ans)

class SegmentTree:
    def __init__(self, n=None, f=max, zero_factory=int, converter=lambda x:x, initial_values=None):
        assert(n or initial_values)
        size = n if n else len(initial_values)
        self.__f, self.__z, self.__c = f, zero_factory, converter
        self.__n = 1 << ((size - 1).bit_length())
        self.__dat = [zero_factory() for _ in range(2 * self.__n)]
        if initial_values:
            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()

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.buffer.readline
def main():
    N = int(input())
    S = list(input().rstrip().decode())

    c = lambda x: ord(x) - ord('a')
    tree = [SegmentTree(N, lambda x,y:x|y) for _ in range(26)]
    for i, l in enumerate(S):
        tree[c(l)].update(i, 1)

    Q = int(input())
    for _ in range(Q):
        t, a, b = input().rstrip().decode().split()
        if t == '1':
            a = int(a) - 1
            tree[c(S[a])].update(a, 0)
            tree[c(b)].update(a, 1)
            S[a] = b
        else:
            a, b = int(a)-1, int(b)-1
            ans = 0
            for i in range(26):
                t = tree[i].query(a, b+1)
                ans += 1 if t else 0
            print(ans)

class SegmentTree:
    def __init__(self, n=None, f=max, zero_factory=int, converter=lambda x:x, initial_values=None):
        assert(n or initial_values)
        size = n if n else len(initial_values)
        self.__f, self.__z, self.__c = f, zero_factory, converter
        self.__n = 1 << ((size - 1).bit_length())
        self.__dat = [zero_factory() for _ in range(2 * self.__n)]
        if initial_values:
            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()

Submission status: Accepted

Solution code:
class SegmentTree:
    def __init__(self, initial_values, f=max, zero=0, converter=lambda x:x):
        self.__f, self.__z, self.__c, self.__size = f, zero, converter, len(initial_values)
        self.__n = 1 << ((self.__size - 1).bit_length())
        self.__dat = [zero] * (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

import sys
input = sys.stdin.readline
N = int(input())
S = input().rstrip()
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().rstrip().split()
    if t == '1': update(int(a)-1, b)
    else: print(bin(query(int(a)-1, int(b))).count('1'))

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline
def main():
    N = int(input())
    S = ['$'] + list(input().rstrip())

    c = lambda x: ord(x) - ord('a')
    bit = [BinaryIndexedTree(N) for _ in range(26)]
    for i, l in enumerate(S):
        if i == 0: continue
        bit[c(l)].add(i, 1)

    Q = int(input())
    for _ in range(Q):
        t, a, b = input().rstrip().split()
        if t == '1':
            a = int(a)
            bit[c(S[a])].add(a, -1)
            bit[c(b)].add(a, 1)
            S[a] = b
        else:
            a, b = int(a), int(b)
            ans = 0
            for i in range(26):
                t = bit[i].sum(b)
                if a >= 1: t -= bit[i].sum(a-1)
                ans += 1 if t else 0
            print(ans)

class BinaryIndexedTree:
    def __init__(self, n=None, f=lambda x,y:x+y, zero=0, initial_values=None):
        assert(n or initial_values)
        self.__f, self.__z, = f, zero
        self.__n = n if n else len(initial_values)
        self.__dat = [zero] * (self.__n + 1)
        if initial_values:
            for i in range(1, self.__n + 1): self.add(i, initial_values[i-1]) #slow

    def add(self, i, v):
        while i <= self.__n:
            self.__dat[i] = self.__f(self.__dat[i], v)
            i += -i&i

    def sum(self, r):
        ans = self.__z
        while r:
            ans = self.__f(ans, self.__dat[r])
            r -= -r&r
        return ans

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline
def main():
    N = int(input())
    S = list(input().rstrip())

    c = lambda x: ord(x) - ord('a')
    tree = [SegmentTree(N, lambda x,y:x|y) for _ in range(26)]
    for i, l in enumerate(S):
        tree[c(l)].update(i, 1)

    Q = int(input())
    for _ in range(Q):
        t, a, b = input().rstrip().split()
        if t == '1':
            a = int(a) - 1
            tree[c(S[a])].update(a, 0)
            tree[c(b)].update(a, 1)
            S[a] = b
        else:
            a, b = int(a)-1, int(b)-1
            ans = 0
            for i in range(26):
                t = tree[i].query(a, b+1)
                ans += 1 if t else 0
            print(ans)

class SegmentTree:
    def __init__(self, n=None, f=max, zero_factory=int, converter=lambda x:x, initial_values=None):
        assert(n, initial_values)
        size = n if n else len(initial_values)
        self.__f, self.__z, self.__c = f, zero_factory, converter
        self.__n = 1 << ((size - 1).bit_length())
        self.__dat = [zero_factory() for _ in range(2 * self.__n)]
        if initial_values:
            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()

Submission status: Accepted

Solution code:
def main():
    N = int(input())
    S = ['$'] + list(input())

    c = lambda x: ord(x) - ord('a')
    bit = [BinaryIndexedTree(N) for _ in range(26)]
    for i, l in enumerate(S):
        if i == 0: continue
        bit[c(l)].add(i, 1)

    Q = int(input())
    for _ in range(Q):
        t, a, b = input().split()
        if t == '1':
            a = int(a)
            bit[c(S[a])].add(a, -1)
            bit[c(b)].add(a, 1)
            S[a] = b
        else:
            a, b = int(a), int(b)
            ans = 0
            for i in range(26):
                t = bit[i].sum(b)
                if a >= 1: t -= bit[i].sum(a-1)
                ans += 1 if t else 0
            print(ans)

class BinaryIndexedTree:
    def __init__(self, n=None, f=lambda x,y:x+y, zero=0, initial_values=None):
        assert(n or initial_values)
        self.__f, self.__z, = f, zero
        self.__n = n if n else len(initial_values)
        self.__dat = [zero] * (self.__n + 1)
        if initial_values:
            for i in range(1, self.__n + 1): self.add(i, initial_values[i-1]) #slow

    def add(self, i, v):
        while i <= self.__n:
            self.__dat[i] = self.__f(self.__dat[i], v)
            i += -i&i

    def sum(self, r):
        ans = self.__z
        while r:
            ans = self.__f(ans, self.__dat[r])
            r -= -r&r
        return ans

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
#####segfunc######
class SegTree:
    def segfunc(self, x, y):
        return max(x,y)

    def __init__(self, init_val):
        #set_val
        #####単位元######
        self.ide_ele = 0
        n = len(init_val)
        #num:n以上の最小の2のべき乗
        self.num =2**(n-1).bit_length()
        self.seg=[self.ide_ele]*2*self.num
        for i in range(n):
            self.seg[i+self.num-1]=init_val[i]    
        #built
        for i in range(self.num-2,-1,-1) :
            self.seg[i]=self.segfunc(self.seg[2*i+1],self.seg[2*i+2]) 
        
    def update(self, k, x):
        k += self.num-1
        self.seg[k] = x
        while k:
            k = (k-1)//2
            self.seg[k] = self.segfunc(self.seg[k*2+1],self.seg[k*2+2])
    def query(self, p, q):
        if q<=p:
            return self.ide_ele
        p += self.num-1
        q += self.num-2
        res=self.ide_ele
        while q-p>1:
            if p&1 == 0:
                res = self.segfunc(res,self.seg[p])
            if q&1 == 1:
                res = self.segfunc(res,self.seg[q])
                q -= 1
            p = p//2
            q = (q-1)//2
        if p == q:
            res = self.segfunc(res,self.seg[p])
        else:
            res = self.segfunc(self.segfunc(res,self.seg[p]),self.seg[q])
        return res



N = int(input())

S = list(input())
ALPHAS = [[0] * (N+1) for i in range(26)]
alpha2num = lambda c: ord(c) - ord('a')
for i in range(N):
    ALPHAS[alpha2num(S[i])][i] = 1
for i,alpha in enumerate(ALPHAS):
    ALPHAS[i] = SegTree(alpha)
ALPHAS = tuple(ALPHAS)
Q = int(input())
for _ in range(Q):
    q,a,b = map(lambda c:c,input().split())
    if q == '2':
        l = int(a)-1
        r = int(b)
        ans = 0
        for i in range(26):
            ans += ALPHAS[i].query(l,r)
        print(ans)
    if q == '1':
        i = int(a)-1
        p_s = S[i]
        s = b
        S[i] = s
        ALPHAS[alpha2num(p_s)].update(i,0)
        ALPHAS[alpha2num(s)].update(i,1)