Official
D - Masking Tape Editorial
by
D - Masking Tape Editorial
by
harurun4635
クエリ \(1\) は「タイルが置かれているかどうか」の bool 列を切り替えることで \(O(1)\) で処理できそうです。
しかし、クエリ \(2\) は愚直には「すべてのマスについて、タイルが置かれているか確認し、置かれていないのであれば色を塗り替える」ことが必要です。これにより色が変わるタイルは、最悪 \(\Theta (N)\) あり、簡単には \(\Theta(NQ)\) です。
上のアルゴリズムで無駄な点を考えてみましょう。これは「毎回色を塗り直している」点です。結果として欲しいものは、最終的な色だけですから、これさえ計算できれば良いです。
様々な方法がありますが、直感的な方法としては
- クエリを前から見て、「最後にタイルが覆われているか」を求める。
- クエリを後ろから見て、色を塗るクエリが来たとき、「まだ色が塗られていない」かつ「タイルに覆われていない」マスにだけ色をぬる
ができれば、各マスについて、一度だけ色を塗ることができます。これは、具体的には次のようにすると実現できます。
「まだ色が塗られていない」かつ「タイルに覆われていない」マスの集合 \(S\) を管理して、後ろからクエリを見る。
タイプ \(1\)
タイルの状態を変化させる。もし \(S\) の集合を変化させるのであれば、\(S\) を更新する。
タイプ \(2\)
\(S\) の要素すべてに色を塗り、集合 \(S\) を空にする。
とすれば良いです。計算量は、集合の挿入・削除を \(O(1)\) とすれば \(O(Q + N)\) です。
実装例 (PyPy)
n, q = map(int, input().split())
qry = [(2, "a")]
tile = [0] * n
for i in range(q):
t, x = input().split()
if t == "1":
x = int(x) - 1
tile[x] ^= 1
qry.append((1, x))
else:
qry.append((2, x))
s = set(i for i in range(n) if tile[i] == 0)
ans = [""] * n
for t, x in reversed(qry):
if t == 1:
if tile[x] == 0 and ans[x] == "":
s.remove(x)
if tile[x] and ans[x] == "":
s.add(x)
tile[x] ^= 1
else:
for i in s:
ans[i] = x
s.clear()
print("".join(ans))