Hướng giải của Cộng Đoạn Lưới Tính Tổng
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Tác giả:
Hướng dẫn giải
Đây là bài toán nâng cao: Cập nhật đoạn trên lưới 2D (Range Update 2D) và tính tổng trên đoạn lưới 2D (Range Query 2D). Để giải quyết trong thời gian \(O(\log N \log M)\), ta cần sử dụng 4 cây BIT 2D độc lập.
Theo công thức mảng hiệu 2D, tổng tiền tố từ \((1, 1)\) đến \((x, y)\) khi thực hiện cập nhật \(val\) tại vị trí \((u, v)\) có dạng: \[S(x, y) = \sum_{i=1}^x \sum_{j=1}^y A[i][j] = \sum_{i=1}^x \sum_{j=1}^y \sum_{u=1}^i \sum_{v=1}^j D[u][v]\]
Khai triển công thức này, ta được: \[S(x, y) = \sum_{u=1}^x \sum_{v=1}^y D[u][v] \cdot (x - u + 1) \cdot (y - v + 1)\] \[S(x, y) = (x+1)(y+1)\sum D[u][v] - (y+1)\sum (u-1)D[u][v] - (x+1)\sum (v-1)D[u][v] + \sum (u-1)(v-1)D[u][v]\]
Do đó, ta cần duy trì 4 cây BIT 2D để quản lý các giá trị:
- \(D[u][v]\)
- \(D[u][v] \cdot (u-1)\)
- \(D[u][v] \cdot (v-1)\)
- \(D[u][v] \cdot (u-1)(v-1)\)
Mã nguồn C++ mẫu
#include <bits/stdc++.h>
using namespace std;
int n, m, q;
vector<vector<long long>> bit1, bit2, bit3, bit4;
void update(vector<vector<long long>>& bit, int x, int y, long long val) {
for (int i = x; i <= n; i += i & -i) {
for (int j = y; j <= m; j += j & -j) {
bit[i][j] += val;
}
}
}
void update_point(int x, int y, long long val) {
update(bit1, x, y, val);
update(bit2, x, y, val * (x - 1));
update(bit3, x, y, val * (y - 1));
update(bit4, x, y, val * (x - 1) * (y - 1));
}
void range_update(int x1, int y1, int x2, int y2, long long val) {
update_point(x1, y1, val);
update_point(x1, y2 + 1, -val);
update_point(x2 + 1, y1, -val);
update_point(x2 + 1, y2 + 1, val);
}
long long query(const vector<vector<long long>>& bit, int x, int y) {
long long s = 0;
for (int i = x; i > 0; i -= i & -i) {
for (int j = y; j > 0; j -= j & -j) {
s += bit[i][j];
}
}
return s;
}
long long prefix_query(int x, int y) {
return query(bit1, x, y) * x * y
- query(bit2, x, y) * y
- query(bit3, x, y) * x
+ query(bit4, x, y);
}
long long range_query(int x1, int y1, int x2, int y2) {
return prefix_query(x2, y2) - prefix_query(x1 - 1, y2)
- prefix_query(x2, y1 - 1) + prefix_query(x1 - 1, y1 - 1);
}
int main(){
ios_base::sync_with_stdio(false); cin.tie(NULL);
if (!(cin >> n >> m >> q)) return 0;
bit1.assign(n + 2, vector<long long>(m + 2, 0));
bit2.assign(n + 2, vector<long long>(m + 2, 0));
bit3.assign(n + 2, vector<long long>(m + 2, 0));
bit4.assign(n + 2, vector<long long>(m + 2, 0));
while (q--) {
int t; cin >> t;
if (t == 1) {
int x1, y1, x2, y2; long long val; cin >> x1 >> y1 >> x2 >> y2 >> val;
range_update(x1, y1, x2, y2, val);
} else {
int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
cout << range_query(x1, y1, x2, y2) << "\n";
}
}
}
Nhận xét