虚空と光明のディスクール(HARD MODE) - jin_matakich 強化コンテスト(extended) F

かしこいかわいいBIT.

解法

X方向の加算,Y方向の加算に分ける.
それぞれについて,左(上)との差を考えると,区間への加算,区間和を求めることができればいいと分かる.
これはBITやSegment Treeでできる.imos法+累積和でもできるらしい.

コード

ライブラリ部分は省略しています.

// Wrongri-La Shower

#include <cstdio>
#include <array>

typedef long long ll;

template <typename T, int n>
class BIT{};

template <typename T, int n>
class CuteCleverBIT{};

int W, H, N, Q;
// bits: X, bits2: Y
CuteCleverBIT<ll,3000> bits[3001], bits2[3001];
ll map[3001][3001];

int main(){
    scanf("%d %d %d %d", &W, &H, &N, &Q);

    for(int i=0;i<N;i++){
        int x, y, a;
        scanf("%d %d %d", &x, &y, &a);

        int l = std::max(x-a+1, 1), r = std::min(x+a-1, W),
            t = std::max(y-a+1, 1), b = std::min(y+a-1, H);

        bits[y].add(l, l+1, a-(x-l));
        bits[y].add(l+1, x+1, 1);
        bits[y].add(x+1, r+2, -1);

        bits2[x].add(t, t+1, a-(y-t));
        bits2[x].add(t+1, y, 1);
        bits2[x].add(y, y+1, -(a-1));
        bits2[x].add(y+1, y+2, a-1);
        bits2[x].add(y+2, b+2, -1);
    }

    for(int i=1;i<=H;i++){
        for(int j=1;j<=W;j++){
            map[i][j] = bits[i].sum(j+1);
        }
    }

    for(int i=1;i<=W;i++){
        for(int j=1;j<=H;j++){
            map[j][i] += bits2[i].sum(j+1);
        }
    }

    for(int i=0;i<Q;i++){
        int x, y;
        scanf("%d %d", &x, &y);

        printf("%lld\n", map[y][x]);
    }
}