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:
def main():
    import sys
    input = sys.stdin.readline

    n = int(input().rstrip('\n'))
    s = input().rstrip('\n')
    q = int(input().rstrip('\n'))
    Q = []

    for _ in range(q):
        Q.append(input().rstrip().split())

    class SegTree():
        def __init__(self, n_):
            self.n = 1
            while self.n < n_:
                self.n *= 2
            self.tree = []
            for _ in range(2 * self.n - 1):
                self.tree.append(2)
        def update(self, k, a):
            k += self.n - 1
            self.tree[k] = a
            while k > 0:
                k = (k - 1) // 2
                self.tree[k] = min(self.tree[k * 2 + 1], self.tree[k * 2 + 2])
        def query(self, l, r):
            l += self.n - 1
            r += self.n - 2
            res = 2
            while r-l>1:
                if l&1 == 0:
                    res = min(res,self.tree[l])
                if r&1 == 1:
                    res = min(res,self.tree[r])
                    r -= 1
                l = l//2
                r = (r-1)//2
            if l == r:
                res = min(res,self.tree[l])
            else:
                res = min(min(res,self.tree[l]),self.tree[r])
            return res

    d = { c: SegTree(n) for c in "abcdefghijklmnopqrstuvwxyz"}
    l = []

    for i, c in enumerate(s):
        d[c].update(i, 1)
        l.append(c)

    for a, b, c in Q:
        if a == "1":
            b = int(b) - 1
            d[l[b]].update(b, 2)
            d[c].update(b, 1)
            l[b] = c
        else:
            res = 0
            b, c = int(b), int(c)
            for key in d:
                if d[key].query(b-1, c) == 1:
                    res += 1
            print(res)


if __name__ == '__main__':
    main()

Submission status: Accepted

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

n = int(input().rstrip('\n'))
s = input().rstrip('\n')
q = int(input().rstrip('\n'))
Q = []

for _ in range(q):
    Q.append(input().rstrip().split())

class SegTree():
    def __init__(self, n_):
        self.n = 1
        while self.n < n_:
            self.n *= 2
        self.tree = []
        for _ in range(2 * self.n - 1):
            self.tree.append(2)
    def update(self, k, a):
        k += self.n - 1
        self.tree[k] = a
        while k > 0:
            k = (k - 1) // 2
            self.tree[k] = min(self.tree[k * 2 + 1], self.tree[k * 2 + 2])
    def query(self, l, r):
        l += self.n - 1
        r += self.n - 2
        res = 2
        while r-l>1:
            if l&1 == 0:
                res = min(res,self.tree[l])
            if r&1 == 1:
                res = min(res,self.tree[r])
                r -= 1
            l = l//2
            r = (r-1)//2
        if l == r:
            res = min(res,self.tree[l])
        else:
            res = min(min(res,self.tree[l]),self.tree[r])
        return res

d = { c: SegTree(n) for c in "abcdefghijklmnopqrstuvwxyz"}
l = []

for i, c in enumerate(s):
    d[c].update(i, 1)
    l.append(c)

for a, b, c in Q:
    if a == "1":
        b = int(b) - 1
        d[l[b]].update(b, 2)
        d[c].update(b, 1)
        l[b] = c
    else:
        res = 0
        b, c = int(b), int(c)
        for key in d:
            if d[key].query(b-1, c) == 1:
                res += 1
        print(res)

Submission status: Accepted

Solution code:
import math

n = int(input())
s = input()
S = [ord(i) - 97 for i in s]
q = int(input())
HEIGHT = math.ceil(math.log(n) / math.log(2))
SIZE = 1 << HEIGHT

def build_tree():
    tree = [0 for _ in range(SIZE<<1)]

    for i, letter in enumerate(s):
        tree[i+SIZE] = 1<<(ord(letter)-97)

    for i in range(HEIGHT - 1, -1, -1):
        for x in range(1<<i, 2<<i):
            tree[x] = tree[x<<1] | tree[(x<<1)+1]

    return tree




def update(x, number):
    tree[x] = number
    while x > 1:
        x >>= 1
        tree[x] = tree[x << 1] | tree[(x << 1) + 1]


def query(l, r):
    total = 0
    while l < r:
        if l&1:
            total |= tree[l]
            l += 1
        l >>= 1
        if r&1:
            r -= 1
            total |= tree[r]
        r >>= 1
    return bin(total).count('1')



tree = build_tree()

for i in range(q):
    a, b, c = input().split()
    b = int(b) - 1
    if int(a) == 1:
        update(b + SIZE, S[b])
        c = 1 << (ord(c) - 97)
        S[b] = c
        update(b + SIZE, c)
    else:
        print(query(b + SIZE, int(c)+SIZE))

Submission status: Accepted

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

    def __init__(self):
        pass

    def load(self, l):
        # len(l)個よりも大きい2の二乗を得る
        self.lenOriginalList = len(l)
        self.lenTreeList = 2 ** (len(l) - 1).bit_length()  # len 5 なら 2^3 = 8
        self.depthTreeList = (len(l) - 1).bit_length()  # 木の段数(0 origin)
        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]
        """
        # print("setValue: {0}, {1}".format(i, a))
        nodeId = (self.lenTreeList - 1) + i
        # print(" first nodeId: {0}".format(nodeId))
        self.dat[nodeId] = a
        while nodeId != 0:
            nodeId = (nodeId - 1) // 2
            # print(" next nodeId: {0}".format(nodeId))
            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の結果を返す
        """
        # print("querySub: a={0}, b={1}, nodeId={2}, l={3}, r={4}".format(a, b, nodeId, l, r))
        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)

### ここまでライブラリ ###

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") # 置き換える文字のaからの距離
        st.setValue(x-1, 1 << nind)
    elif ty == "2":
        x = int(x) - 1 # 1 origin -> 0 origin
        y = int(y)  # こっちは開区間なのでこのまま
        res = 0
        cnt = st.query(x, y)
        print(bin(cnt).count("1")) # popcount()
    else:
        print("error")

Submission status: Accepted

Solution code:
# https://atcoder.jp/contests/abc157/tasks/abc157_e
# セグメント木
# 各文字をビットに対応させる(セグ木を26本持っても良い)
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()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −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  # ここで半開区間でなく[l,r]で以下を処理する
        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]

# build segment tree
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)))

Submission status: Accepted

Solution code:
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:
#				print(f"({s} - {e})")
				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:
#			print(f"#{w}: " + ", ".join(func(data) for data in data_list))
			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)
#st.check(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
		
#		st.check(merge)
		
	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
#		st.output(lambda data: "".join(chr(A + j) + str(data[j]) if data[j] > 0 else "" for j in range(26)))
		
		print(count)
#		print("".join(set2str(data) for data in st.data_table[0][1]))

Submission status: Accepted

Solution code:


# # # # class Segtree # # # #

#      0
#   1     2
# 3   4  5  6
#       :
# leaf i - n-1+i
# parent   - (i-1)//2
# children - 2*i+1, 2*i+2

class Segtree:
    # modify UNIT and oper depending on the reduce operation

    #UNIT = 0  # sum/or:0 and:fff..f min:BIG max:-BIG gcd:0 lcm:1 ..

    #@classmethod
    #def oper(c,x,y):
    #    return x|y  # sum:+ or/and/min/max/gcd/lcm:(same)

    # call like this: sgt = Segtree(n, 0, lambda x,y: max(x,y))

    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)

    # x,y: from query  k: suffix at focus l,r: range for k
    # right ends (y,r) not included

    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)

# # # # class Segtree end # # # #


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

#ddprint("tree")
#for c in alpha:
#    ddprint(c)
#    ddprint(tr[c])

q = inn()
for qq in range(q):
    x,y,z = input().split()
    #ddprint(f"x {x} y {y} z {z}")
    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)

Submission status: Accepted

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

Submission status: Accepted

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

Submission status: Accepted

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

Submission status: Accepted

Solution code:
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)
#print(ss)

def update(j, v):
    ss[0][j] = v
    for k in range(1, len(ss)):
        j = j // 2
        #print('k=', k, 'j=', j)
        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]
    #print('j=', j, 'v=', v, 'ss=', ss)

def all_or(i, j, k):
    #print('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)
        #print('i=', i, 'j=', j, 'k=', k, 'ik=', ik, 'jk=', jk)
        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:
        #print('cs[2]=', cs[2], 'mask=', 1 << (ord(cs[2]) - ord('a')))
        update(cs[1], (1 << (ord(cs[2]) - ord('a'))))
    else:
        #print('all_or(', cs[1], int(cs[2]), ')=',all_or(cs[1], int(cs[2]), len(ss) - 1))
        #r = 0
        #for j in range(cs[1], int(cs[2])):
        #    r |= ss[0][j]
        print(popcount(all_or(cs[1], int(cs[2]), len(ss) - 1)))
        #print(popcount(r))

Submission status: Accepted

Solution code:
# coding: UTF-8
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()

Submission status: Accepted

Solution code:
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')
    # print(tmp)
    for j in range(26):
        if j == tmp:
            acc[i+1][j] = acc[i][j] + 1
            continue
        acc[i+1][j] = acc[i][j]
# print(acc)
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)
# print(upd)