pythonで青くなるブログ

主に競プロのについての記事(日記的な)を書きます。現在atcoder水色,こどふぉ青色。python3使って、やってます。atcoder青くなりたい

CodeForces Round #590 Div3 D, Distinct Characters Queries

内容

CFのRound #590 Div3のD問題、Distinct Characters Queriesをpythonで解きました。

問題

文字列S(アルファベット小文字)とQ個のクエリが与えられる。
クエリは二種類あって、

  • (1 x y) -> 文字列のx番目の文字を、yに書き換える。
  • (2 l r) -> 文字列の[l,r]区間にある文字の種類数を答える。   

です。

 制約

  • |S|<=10**5
  • q<=10**5
  • 出てくる文字は、全てアルファベットの小文字(26種)

考えたこと

  • 変更クエリと、値を求めるクエリ-> セグ木! と考えて、セグ木で解きました。

ポイント

  • 初めは、木のノードをset()にしてて、 par = child1 | child2で更新してたけど、TLE
  • アルファベットは26種しかないので 26桁のbitで、区間内に含まれる文字を管理するようにしたら、TLEが取れた。

実装

import sys
sys.setrecursionlimit(10**9)
input = sys.stdin.readline


class SegmentTree():
    def __init__(self, n):
        self.n = 2**(n-1).bit_length()
        self.data = [0 for _ in range(2*self.n)]

    def set(self, k, v):
        v_val = ord(v)-ord('a') #アルファベットを数字にする。'a'->1, 'b'->2 ..
        self.data[k+self.n-1] = 1 << v_val #含むアルファベットをbitで管理

    def build(self):
        for k in reversed(range(self.n-1)):
            self.data[k] = self.data[k*2+1] | self.data[k*2+2] 

    def update(self, k, a):
        k += self.n-1
        v_val = ord(a)-ord("a")
        self.data[k] = 1 << v_val

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

    def query(self, l, r):
        L = l+self.n
        R = r+self.n
        ret = 0
        while L < R:
            if R & 1:
                R -= 1
                ret |= self.data[R-1]
            if L & 1:
                ret |= self.data[L-1]
                L += 1
            L >>= 1
            R >>= 1
        return ret


S = [v for v in input()[:-1]]
N = len(S)
Q = int(input())
query = [[v for v in input()[:-1].split()] for _ in range(Q)]

Seg = SegmentTree(N)
for i, s in enumerate(S):
    Seg.set(i, s)

Seg.build()

for q, v1, v2 in query:
    if q == "1":
        Seg.update(int(v1)-1, v2)
    else:
        val = Seg.query(int(v1)-1, int(v2))
        print(bin(val)[2:].count("1"))

終わりに

  • セグ木いいですね。