Official

D - 配達圏内の売上合計 / Total Sales Within Delivery Range Editorial by sounansya


まず、座標 \((x,y)\) に対して変数変換 \((u,v)=(x+y,x-y)\) を行います。これは マンハッタン距離の \(45\) 度回転 と呼ばれるものです。

\((X_i,Y_i)\) に対し \(45\) 度回転を行った後の座標を \((X_i',Y_i')\) とします。\((P_i',Q_i')\) も同様に定義します。

すると、\(|X_i-P_j|+|Y_i-Q_j| \le K_j\) という条件は \(\max(|X_i'-P_j'|,|Y_i'-Q_j'|) \le K_j\) と言い換えることができます。これは座標 \((X_i',Y_i')\) を中心とする一辺の長さが \(2K_j\) の正方形です。つまり、各クエリでは正方形が与えられ、正方形内の店舗の売上の合計を高速に求めれば良いことになります。

そして、これには二次元累積和を使うことができます。与えられた店舗に対して二次元累積和を取り、各クエリではそれらの差分を計算すれば良いです。

以上を適切に実装することでこの問題に正答することができます。\(45\) 度回転を行った結果座標の値が負になる場合があることに注意してください。以下の実装例では適当な offset を付けることでこの問題を回避しています。

実装例(Python3)

import sys
input = sys.stdin.readline

INF = 2005
SIZE = 4 * INF + 1

a = [[0] * SIZE for _ in range(SIZE)]

n, m = map(int, input().split())

for _ in range(n):
    x, y, c = map(int, input().split())
    u = x + y + INF
    v = x - y + 2 * INF
    a[u][v] += c

for i in range(4 * INF):
    ai = a[i]
    ni = a[i + 1]
    for j in range(SIZE):
        ni[j] += ai[j]

for i in range(SIZE):
    row = a[i]
    for j in range(4 * INF):
        row[j + 1] += row[j]


for _ in range(m):
    x, y, c = map(int, input().split())
    u = x + y + INF
    v = x - y + 2 * INF

    ans = (
        a[u + c][v + c]
        - a[u - c - 1][v + c]
        - a[u + c][v - c - 1]
        + a[u - c - 1][v - c - 1]
    )
    print(ans)

posted:
last update: