ABC 366

Table of Contents

https://atcoder.jp/contests/abc366

D - Cuboid Sum Query

3次元累積和の問題

https://atcoder.jp/contests/abc366/tasks/abc366_d

$f_i(a,b) = \sum_{i=a}^{b}$ とする。

\begin{align} \sum_{i=a}^{x} &\sum_{i=b}^{y} \sum_{i=c}^{z} \nonumber = f_i(a,x)f_j(b,y)f_k(c,z) \nonumber \\ &= \left\{ f_i(1,x) - f_i(1,a-1) \right\} \nonumber \\ &~~~ \times \left\{ f_j(1,y) - f_j(1,b-1) \right\} \nonumber \\ &~~~ \times \left\{ f_k(1,z) - f_k(1,c-1) \right\} \nonumber \\ &= f_i(1,x)f_j(1,y)f_k(1,z) - f_i(1,x)f_j(1,y)f_k(1,c-1) \nonumber \\ &~~~ - f_i(1,x)f_j(1,b-1)f_k(1,z) + f_i(1,x)f_j(1,b-1)f_k(1,c-1) \nonumber \\ &~~~ - f_i(1,a-1)f_j(1,y)f_k(1,z) + f_i(1,a-1)f_j(1,y)f_k(1,c-1) \nonumber \\ &~~~ + f_i(1,a-1)f_j(1,b-1)f_k(1,z) - f_i(1,a-1)f_j(1,b-1)f_k(1,c-1) \nonumber \\ \end{align}

これより $\displaystyle S_{x,y,z} = \sum_{i=1}^{x} \sum_{j=1}^{y} \sum_{k=1}^{z} A_{i,j,k}$ とすると

\begin{align} \sum_{i=a}^{x} &\sum_{i=b}^{y} \sum_{i=c}^{z} A_{i,j,k} \nonumber \\ &= S_{x,y,z} - S_{x,y,c-1}- S_{x,b-1,z} + S_{x,b-1,c-1} \nonumber \\ &~~~ - S_{a-1,y,z} + S_{a-1,y,c-1} + S_{a-1,b-1,z} - S_{a-1,b-1,c-1} \nonumber \end{align}

3次元累積和がわかっているときに部分的な累積和を求める方法はわかった。

次に3次元累積和の構成方法について考える。

\begin{align} f_i(1,x)&f_j(1,y)f_k(1,z) \nonumber \\ &= \left\{ f_i(x,x) + f_i(1,x-1) \right\} \nonumber \\ &~~~ \times \left\{ f_j(y,y) + f_j(1,y-1) \right\} \nonumber \\ &~~~ \times \left\{ f_k(z,z) + f_k(1,z-1) \right\} \nonumber \\ &= f_i(x,x)f_j(y,y)f_k(z,z) + f_i(x,x)f_j(y,y)f_k(1,z-1) \nonumber \\ &~~~ + f_i(x,x)f_j(1,y-1)f_k(z,z) + f_i(x,x)f_j(1,y-1)f_k(1,z-1) \nonumber \\ &~~~ + f_i(1,x-1)f_j(y,y)f_k(z,z) + f_i(1,x-1)f_j(y,y)f_k(1,z-1) \nonumber \\ &~~~ + f_i(1,x-1)f_j(1,y-1)f_k(z,z) + f_i(1,x-1)f_j(1,y-1)f_k(1,z-1) \nonumber \end{align}

\begin{align} f_i(x,x)&f_j(y,y)f_k(1,z-1) \nonumber \\ &= \left\{ f_i(1,x) - f_i(1,x-1) \right\} \left\{ f_j(1,y) - f_j(1,y-1) \right\} f_k(1,z-1) \nonumber \\ &= f_i(1,x)f_j(1,y)f_k(1,z-1) - f_i(1,x)f_j(1,y-1)f_k(1,z-1) \nonumber \\ &~~~ - f_i(1,x-1)f_j(1,y)f_k(1,z-1) + f_i(1,x-1)f_j(1,y-1)f_k(1,z-1) \nonumber \end{align}

\begin{align} f_i(x,x)&f_j(1,y-1)f_k(z,z) \nonumber \\ &= \left\{ f_i(1,x) - f_i(1,x-1) \right\} f_j(1,y-1) \left\{ f_k(1,z) - f_k(1,z-1) \right\}\nonumber \\ &= f_i(1,x)f_j(1,y-1)f_k(1,z) - f_i(1,x)f_j(1,y-1)f_k(1,z-1) \nonumber \\ &~~~ - f_i(1,x-1)f_j(1,y-1)f_k(1,z) + f_i(1,x-1)f_j(1,y-1)f_k(1,z-1) \nonumber \end{align}

\begin{align} f_i(1,x-1)&f_j(y,y)f_k(z,z) \nonumber \\ &= f_i(1,x-1) \left\{ f_j(1,y) - f_j(1,y-1) \right\} \left\{ f_k(1,z) - f_k(1,z-1) \right\}\nonumber \\ &= f_i(1,x-1)f_j(1,y)f_k(1,z) - f_i(1,x-1)f_j(1,y)f_k(1,z-1) \nonumber \\ &~~~ - f_i(1,x-1)f_j(1,y-1)f_k(1,z) + f_i(1,x-1)f_j(1,y-1)f_k(1,z-1) \nonumber \end{align}

\begin{align} f_i(x,x)&f_j(1,y-1)f_k(1,z-1) \nonumber \\ &= \left\{ f_i(1,x) - f_i(1,x-1) \right\} f_j(1,y-1) f_k(1,z-1) \nonumber \\ &= f_i(1,x)f_j(1,y-1) f_k(1,z-1) - f_i(1,x-1)f_j(1,y-1)f_k(1,z-1) \nonumber \end{align}

\begin{align} f_i(1,x-1)&f_j(y,y)f_k(1,z-1) \nonumber \\ &= f_i(1,x-1) \left\{ f_j(1,y) - f_j(1,y-1) \right\} f_k(1,z-1) \nonumber \\ &= f_i(1,x-1)f_j(1,y)f_k(1,z-1) - f_i(1,x-1)f_j(1,y-1)f_k(1,z-1) \nonumber \end{align}

\begin{align} f_i(1,x-1)&f_j(1,y-1)f_k(z,z) \nonumber \\ &= f_i(1,x-1) f(1,y-1)\left\{ f_k(1,z) - f_k(1,z-1) \right\} \nonumber \\ &= f_i(1,x-1)f_j(1,y-1)f_k(1,z) - f_i(1,x-1)f_j(1,y-1)f_k(1,z-1) \nonumber \end{align}

まとめると

\begin{align} S_{x,y,z} &= A_{x,y,z} + S_{x,y,z-1} + S_{x,y-1,z} - S_{x,y-1,z-1} \nonumber \\ &+ S_{x-1,y,z} - S_{x-1,y,z-1} - S_{x-1,y-1,z} + S_{x-1,y-1,z-1} \nonumber \end{align}

累積和で終点を含む場合

void solve() {
    ll N;
    cin >> N;

    vector<vvll> A(N + 1, vvll(N + 1, vll(N + 1, 0)));
    rep(i, N) {
        rep(j, N) {
            rep(k, N) {
                cin >> A[i + 1][j + 1][k + 1];
            }
        }
    }

    vector<tuple<ll, ll, ll, ll>> d = {
        {0, 0, -1, 1},
        {0, -1, 0, 1},
        {0, -1, -1, -1},
        {-1, 0, 0, 1},
        {-1, 0, -1, -1},
        {-1, -1, 0, -1},
        {-1, -1, -1, 1},
    };

    vector<vvll> cumsum(N + 1, vvll(N + 1, vll(N + 1, 0)));
    rep2(i, 1, N + 1) rep2(j, 1, N + 1) rep2(k, 1, N + 1) {
        cumsum[i][j][k] += A[i][j][k];
        for (auto [x, y, z, sign] : d) {
            cumsum[i][j][k] += cumsum[i + x][j + y][k + z] * sign;
        }
    }

    ll Q;
    cin >> Q;
    while (Q--) {
        ll a, x, b, y, c, z;
        cin >> a >> x >> b >> y >> c >> z;

        ll ans = 0;
        ans += cumsum[x][y][z];
        ans -= cumsum[x][y][c - 1];
        ans -= cumsum[x][b - 1][z];
        ans += cumsum[x][b - 1][c - 1];
        ans -= cumsum[a - 1][y][z];
        ans += cumsum[a - 1][y][c - 1];
        ans += cumsum[a - 1][b - 1][z];
        ans -= cumsum[a - 1][b - 1][c - 1];
        cout << ans << endl;
    }
}

累積和で終点を含まない場合

void solve() {
    ll N;
    cin >> N;

    vector<vvll> A(N, vvll(N, vll(N, 0)));
    rep(i, N) {
        rep(j, N) {
            rep(k, N) {
                cin >> A[i][j][k];
            }
        }
    }

    vector<tuple<ll, ll, ll, ll>> d = {
        {0, 0, -1, 1},
        {0, -1, 0, 1},
        {0, -1, -1, -1},
        {-1, 0, 0, 1},
        {-1, 0, -1, -1},
        {-1, -1, 0, -1},
        {-1, -1, -1, 1},
    };

    vector<vvll> cumsum(N + 1, vvll(N + 1, vll(N + 1, 0)));
    rep2(i, 1, N + 1) rep2(j, 1, N + 1) rep2(k, 1, N + 1) {
        cumsum[i][j][k] += A[i - 1][j - 1][k - 1];
        for (auto [x, y, z, sign] : d) {
            cumsum[i][j][k] += cumsum[i + x][j + y][k + z] * sign;
        }
    }

    ll Q;
    cin >> Q;
    while (Q--) {
        ll a, x, b, y, c, z;
        cin >> a >> x >> b >> y >> c >> z;
        a--, b--, c--;

        ll ans = 0;
        ans += cumsum[x][y][z];
        ans -= cumsum[x][y][c];
        ans -= cumsum[x][b][z];
        ans += cumsum[x][b][c];
        ans -= cumsum[a][y][z];
        ans += cumsum[a][y][c];
        ans += cumsum[a][b][z];
        ans -= cumsum[a][b][c];
        cout << ans << endl;
    }
}