Official

B - 在庫管理システム / Inventory Management System Editorial by MMNMM


この問題は、差分更新の考え方を使って解くことができます。

ある更新の前後で全店舗の在庫の合計がどのように変化するかを考えます。 更新の前における \(i\) 番目 \((1\le i\le N)\) の店舗の在庫数を \(P _ i\) とすると、店舗 \(X\) の在庫数を \(Y\) にする更新によって全店舗の在庫の合計は \(Y-P _ X\) だけ増加します(\(Y-P _ X\) が負のとき、\(-(Y-P _ X)\) だけ減少します)。

よって、次のようなアルゴリズムによってこの問題を解くことができます。

  1. はじめ、\(\displaystyle S\leftarrow\sum _ {i=1} ^ NA _ i\) および \(P _ i=A _ i\ (1\le i\le N)\) と初期化する。
  2. それぞれの更新ごとに、次の操作を行う。
    1. \(S\leftarrow S+Y _ i-P _ {X _ i}\) と更新する。
    2. \(P _ {X _ i}\leftarrow Y _ i\) と更新する。
    3. \(S\) を出力する。

これは、時間計算量 \(O(N+Q)\) 、空間計算量 \(O(N)\) となり、十分高速です。

実装例は以下のようになります。

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int N, Q;
    cin >> N >> Q;

    vector<int> P(N);
    long S = 0;
    for (int& p : P) {
        cin >> p;
        S += p;
    }

    for (int i = 0; i < Q; ++i) {
        int x, y;
        cin >> x >> y;
        --x; // 0-indexed にしておく
        S += y - P[x]; // 差分を足して
        P[x] = y; // P を更新
        cout << S << endl;
    }
    return 0;
}
N, Q = map(int, input().split())

P = list(map(int, input().split()))
S = sum(P)

for i in range(Q):
    x, y = map(int, input().split())
    x -= 1 # 0-indexed にしておく
    S += y - P[x] # 差分を足して
    P[x] = y # P を更新
    print(S)

posted:
last update: