結果
問題 | No.2020 Sum of Common Prefix Length |
ユーザー |
![]() |
提出日時 | 2025-05-01 20:53:37 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 800 ms / 2,000 ms |
コード長 | 2,990 bytes |
コンパイル時間 | 384 ms |
コンパイル使用メモリ | 82,712 KB |
実行使用メモリ | 238,784 KB |
最終ジャッジ日時 | 2025-05-01 20:54:03 |
合計ジャッジ時間 | 23,107 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 38 |
ソースコード
#yukicoder2020 Sum of Common Prefix Length #BITを書く class BinaryTree: def __init__(self, N): self._N = N self._node = [0] * (N + 1) def add(self, i, v): #A[i] += v i += 1 while i <= self._N: self._node[i] += v i += i & - i def sum(self, i): #A[0, 1, ・・・, i] i += 1 ans = 0 while i > 0: ans += self._node[i] i ^= i & - i return ans def fold(self, Lt, Rt): #A[Lt, ・・・, Rt] ans = 0 while Lt != Rt: if Lt > Rt: ans -= self._node[Lt] Lt ^= Lt & - Lt else: ans += self._node[Rt] Rt ^= Rt & - Rt return ans #入力受取 英小文字は[0, 26)に置換 N = int(input()) S = [ [ord(s) - ord('a') for s in input()] for _ in range(N) ] query = [None] * ( Q := int(input()) ) for q in range(Q): t, *x = input().split() if t == '1': query[q] = ( 1, int(x[0]) - 1, ord(x[1]) - ord('a') ) else: query[q] = ( 2, int(x[0]) - 1, 0 ) #初期状態のSの長さをF[i]としておく。SのTrieを構築 F = [len(S[i]) for i in range(N)] for t, x, c in query: if t == 1: S[x].append(c) #S[i]ごとに、各文字を採用後に何番のノードに到達したか記録しておく #Trie木を構築しながら隣接リストを作成 Trie = [[-1] * 26] G = [[]] T = [None] * N for i, Si in enumerate(S): Ti = [0] * len(Si) now = 0 for j, s in enumerate(Si): if ( nxt := Trie[now][s] ) == -1: G[now].append(len(G)) G.append([now]) Trie[now][s] = now = len(Trie) Trie.append([-1] * 26) else: now = nxt Ti[j] = now T[i] = Ti n = len(Trie) del Trie[:], Trie #木DPの形になったのでEuler Tour stack = [0] visit = [0] * n #入りがけ << 31 | 出がけ の時刻 mask = ~ ( - 1 << 31) for t in range(n << 1): if ( now := stack.pop() ) >= 0: visit[now] |= t << 31 stack.append(~ now) for nxt in G[now]: if now < nxt: #Trie木の構造上、子ノードは常に番号が小さい stack.append(nxt) else: visit[now := ~ now] |= t #ETの経路上に1を置く。LCPはETの根からの経路和に等しい #imos法でいいはず 入りがけ時刻に+1 出がけ時刻に-1 BIT = BinaryTree(n << 1) for Ti, Fi in zip(T, F): for f in range(Fi): #node[Ti][f]について区間加算 v = visit[ Ti[f] ] AD, DC = admission, discharge = v >> 31, v & mask BIT.add(AD, + 1) BIT.add(DC, - 1) #クエリを処理 for t, x, c in query: if t == 1: #S[x] += c v = visit[ T[x][ F[x] ] ] AD, DC = v >> 31, v & mask F[x] += 1 BIT.add(AD, + 1) BIT.add(DC, - 1) if t == 2: #fold AD = ( v := visit[ T[x][ F[x] - 1 ] ] ) >> 31 print(BIT.sum(AD))