[R29E] 矩形求和
数据规模:,,,查询的行列范围 。
思路
把 写成二进制后,矩阵元素是逐位贡献的和:
于是矩形 的和可以交换求和顺序:对每个二进制位 ,统计矩形内「行第 位为 、列第 位为 」的格子数,正好等于 (行与列的选择互不影响),其中 是区间 内第 位等于 的整数个数, 同理。所以:
统计第 位为 的个数: 内第 位为 的数有
即每 个一循环,其中后 个的第 位为 。记 ,, 同理,则 ,,列同理。
展开化简:把 、 代入原式并整理:
这样每个查询只需对每个 计算 4 个边界值 的 (),再套用维护好的系数即可。修改操作只改变某一层的 ,更新该层的三个系数 与总和 即可,。
所有计数不超过 ,用 Int64 精确存放;乘法前先取模 ,中间乘积不超过 ,不会溢出。
复杂度
时间 预处理 + 每次操作,空间 。
仓颉实现
查看仓颉实现
import std.env.*
import std.convert.*
main() {
let reader = getStdIn()
let n = Int64.parse(reader.readln().getOrThrow().trimAscii())
let a = Array<Array<Int64>>(n, { _ => Array<Int64>(4, { _ => 0 }) })
for (k in 0..n) {
let line = reader.readln().getOrThrow().split(" ", removeEmpty: true)
a[k][0] = Int64.parse(line[0])
a[k][1] = Int64.parse(line[1])
a[k][2] = Int64.parse(line[2])
a[k][3] = Int64.parse(line[3])
}
let q = Int64.parse(reader.readln().getOrThrow().trimAscii())
let pow2 = Array<Int64>(n + 1, { _ => 1 })
for (k in 1..(n + 1)) {
pow2[k] = pow2[k - 1] * 2
}
let w1 = Array<Int64>(n, { _ => 0 })
let w2 = Array<Int64>(n, { _ => 0 })
let w3 = Array<Int64>(n, { _ => 0 })
var s0: Int64 = 0
for (k in 0..n) {
let a0 = a[k][0]
let a1 = a[k][1]
let a2 = a[k][2]
let a3 = a[k][3]
s0 = (s0 + a0) % 998244353
w1[k] = (a1 - a0 + 998244353) % 998244353
w2[k] = (a2 - a0 + 998244353) % 998244353
w3[k] = ((a0 - a1 - a2 + a3) % 998244353 + 998244353) % 998244353
}
for (_ in 0..q) {
let line = reader.readln().getOrThrow().split(" ", removeEmpty: true)
if (line[0] == "1") {
let k = Int64.parse(line[1])
let c = Int64.parse(line[2])
let v = Int64.parse(line[3])
let old0 = a[k][0]
a[k][c] = v
let a0 = a[k][0]
let a1 = a[k][1]
let a2 = a[k][2]
let a3 = a[k][3]
s0 = (s0 + a0 - old0 % 998244353 + 998244353) % 998244353
w1[k] = (a1 - a0 + 998244353) % 998244353
w2[k] = (a2 - a0 + 998244353) % 998244353
w3[k] = ((a0 - a1 - a2 + a3) % 998244353 + 998244353) % 998244353
} else {
let r1 = Int64.parse(line[1])
let c1 = Int64.parse(line[2])
let r2 = Int64.parse(line[3])
let c2 = Int64.parse(line[4])
let lenR = r2 - r1 + 1
let lenC = c2 - c1 + 1
let lenRm = lenR % 998244353
let lenCm = lenC % 998244353
let tR2 = r2 + 1
let tR1 = r1
let tC2 = c2 + 1
let tC1 = c1
var acc2: Int64 = 0
var acc3: Int64 = 0
var acc4: Int64 = 0
for (k in 0..n) {
let p2 = pow2[k]
let sh = k + 1
var s = tR2 >> sh
var rem = tR2 - (s << sh)
var cnt = s * p2
if (rem > p2) {
cnt += rem - p2
}
var cr1 = cnt
s = tR1 >> sh
rem = tR1 - (s << sh)
cnt = s * p2
if (rem > p2) {
cnt += rem - p2
}
cr1 -= cnt
s = tC2 >> sh
rem = tC2 - (s << sh)
cnt = s * p2
if (rem > p2) {
cnt += rem - p2
}
var cc1 = cnt
s = tC1 >> sh
rem = tC1 - (s << sh)
cnt = s * p2
if (rem > p2) {
cnt += rem - p2
}
cc1 -= cnt
let cr1m = cr1 % 998244353
let cc1m = cc1 % 998244353
acc2 = (acc2 + w1[k] * cc1m) % 998244353
acc3 = (acc3 + w2[k] * cr1m) % 998244353
acc4 = (acc4 + w3[k] * ((cr1m * cc1m) % 998244353)) % 998244353
}
let ans = (((lenRm * lenCm) % 998244353) * s0 + lenRm * acc2 + lenCm * acc3 + acc4) % 998244353
println(ans)
}
}
}