公式

E - E-liter 解説 by evima


各クエリで黒マスが何個増える(減る)か分かれば十分です。以下、タイプ 1 のクエリで黒マスが何個増えるか考えます。

\(R\) が初めて操作対象になったとき、行 \(R\) のマスはすべて白であり、黒マスが \(N\) 個増えます。

\(R\) が操作対象になったのが初めてでないとき、行 \(R\) のマスは行 \(R\) が前回操作対象になったときに黒になっており、その後タイプ 2 のクエリで白く塗られたマスを黒に戻すことになります。

従って、行 \(R\) が前回操作対象になってからタイプ 2 のクエリの対象になった列が何個あるか(あるいは何種類のタイプ 2 のクエリが行われたか)求まれば、それが黒マスの増加数です。

これは AWC0015E の特殊な場合です。ここでそちらの解説に移っても構いませんが、ここでは Fenwick Tree / Binary Indexed Tree(数列の要素の変更と区間和の計算をともに高速に行うデータ構造)を使って今回の特殊な場合を解く方法を述べます。(一般の場合もクエリをソートすれば同様に解けます。)

長さ \(Q\) の数列 \(f\) を Fenwick Tree で管理しながらクエリを順に処理します。\(f_i\) の値は、\(i\) 回目のクエリが実行済みのタイプ 2 のクエリであってその列に対する(その時点で)最後のクエリであるなら \(1\)、そうでないなら \(0\) とします(要するに、各列について最後の \(1\) 回のクエリのみ数えることで同じ列の重複を省きます)。すると、\(i\) 回目のクエリがタイプ 1 であるとき、そこでの黒マスの増加数は、行 \(R\) が前回操作対象になったクエリが \(\text{last}_R\) 回目であるとして \(\sum_{j = \text{last}_R}^{i - 1} f_j\) と計算できます。\(\text{last}_R\) を通常の配列で管理すると、全体の時間計算量は \(O(Q \log Q + N)\) です。

タイプ 2 のクエリで黒マスが何個減るかも同様に求められますが、列 \(C\) が初めて操作対象になったときはそれまでにタイプ 1 のクエリの対象になった行を数えます。


Python(+ AtCoder Library の Python ポート)での実装例

from atcoder.fenwicktree import FenwickTree

N, Q = map(int, input().split())
f = [FenwickTree(Q + 1) for _ in range(2)]
b = 0
last = [[-1] * (N + 1), [0] * (N + 1)]

for i in range(1, Q + 1):
    t, x = map(int, input().split())
    t -= 1
    if last[t][x] == -1:
        b += N
    else:
        kind = f[1 - t].sum(last[t][x], i)
        b += kind if t == 0 else -kind
        f[t].add(last[t][x], -1)
    f[t].add(i, 1)
    last[t][x] = i
    print(b)

投稿日時:
最終更新: