ロリハ
| 投稿者 | urunea |
|---|---|
| 言語 | PyPy3 |
| 更新日時 (JST) | 2026-10-31 20:55:46 |
| サイズ | 3,552 Byte |
| 参照URL | |
日時はサーバーが記録したものです。更新すると更新日時が変わるので、不都合がある場合は新しく投稿してください。
import random
S = input().strip()
N = len(S)
base = random.randint(256, 10**6)
mods = [1000000007, 1000000009]
M = len(mods)
A = [ord(c) - 96 for c in S]
H = [[0]*(N+1) for _ in range(M)]
P = [[1]*(N+1) for _ in range(M)]
for j in range(M):
mod = mods[j]
for i in range(N):
H[j][i+1] = (H[j][i]*base + A[i]) % mod
P[j][i+1] = (P[j][i]*base) % mod
#半開区間[l, r)
def get_hash(l, r):
res = []
for j in range(M):
mod = mods[j]
val = (H[j][r] - H[j][l]*P[j][r-l]) % mod
res.append(val)
return (res[0] << 32) ^ res[1]
#---------------------------------------------------------
import random
# 2つの異なる大きな素数を用意
mod1 = 998244353
mod2 = 1000000007
# 実行ごとに完全に独立したランダム基数を生成(ハック絶対回避)
base1 = random.randint(2, mod1 - 2)
base2 = random.randint(2, mod2 - 2)
# 状態 S: (h1, h2, B1, B2, s1, s2)
# h: 区間のハッシュ値
# B: base^length (左区間をシフトさせる係数)
# s: base^0 + ... + base^(length-1) (一括上書き時の計算用)
def op(x, y):
xh1, xh2, xB1, xB2, xs1, xs2 = x
yh1, yh2, yB1, yB2, ys1, ys2 = y
# 2つのモジュロで全く同じ計算を並行して行う
h1 = (xh1 * yB1 + yh1) % mod1
B1 = (xB1 * yB1) % mod1
s1 = (xs1 * yB1 + ys1) % mod1
h2 = (xh2 * yB2 + yh2) % mod2
B2 = (xB2 * yB2) % mod2
s2 = (xs2 * yB2 + ys2) % mod2
return (h1, h2, B1, B2, s1, s2)
def e():
# 長さ0の単位元
return (0, 0, 1, 1, 0, 0)
def mapping(f, S):
if f == -1: # 操作の単位元
return S
_h1, _h2, B1, B2, s1, s2 = S
# 区間全体を文字 f に上書き
h1 = (f * s1) % mod1
h2 = (f * s2) % mod2
return (h1, h2, B1, B2, s1, s2)
def composition(f, g):
return f if f != -1 else g
def id_v():
return -1
# ==========================================
# 初期化と判定の確実な使い方
# ==========================================
"""
S_str = "abacaba"
# 各文字 c について、初期状態 (h1, h2, base1^1, base2^1, sum_b1, sum_b2) を作る
# 初期長さは1なので、B=base, sum=1 となる
aa = [(ord(c), ord(c), base1, base2, 1, 1) for c in S_str]
seg = LazySegTree(op, e(), mapping, composition, id_v(), aa)
# ハッシュの比較時は、モジュロ1とモジュロ2の両方の値が一致するか確認する
h_left = seg.prod(0, 3) # 戻り値は6要素のタプル
h_right = seg.prod(4, 7)
# h[0]がmod1のハッシュ、h[1]がmod2のハッシュ
if h_left[0] == h_right[0] and h_left[1] == h_right[1]:
print("Match!")
"""
# ==========================================
# クエリ1:区間変更(Range Update)
# ==========================================
# 例: 区間 [1, 4) の文字をすべて "z" に一括で上書き変更する
update_char = ord("z")
seg.apply(1, 4, update_char)
# ==========================================
# クエリ2:一点変更(Point Update)
# ==========================================
# 例: インデックス 2 の文字だけを "x" に変更する
p = 2
new_char = ord("x")
# 方法1: apply を使って「長さ1の区間」として処理する(最も簡潔)
seg.apply(p, p + 1, new_char)
# 方法2: set を使ってノードの状態データを直接上書きする
# ※set の場合は mapping を経由しないため、初期化時と同じ「長さ1の6要素タプル」を直接渡す必要があります
seg.set(p, (new_char, new_char, base1, base2, 1, 1))