Hướng giải của Đếm Cây Nông Trại 2D
Nhớ rằng hướng dẫn giải này chỉ nên sử dụng khi bế tắc, và tuyệt đối không nên sao chép mã nguồn kèm theo. Hãy tôn trọng tác giả bài tập và người viết hướng dẫn giải.
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.
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
Bài toán thực hiện cập nhật điểm và truy vấn tổng vùng trên lưới tọa độ \(N \times M\). Ta sử dụng cấu trúc 2D Fenwick Tree:
- Mỗi thao tác cập nhật tại \((x, y)\) tăng thêm \(val\) được thực hiện bằng cách duyệt qua các hàng và các cột theo quy tắc chỉ số nhị phân:
for (int i = x; i <= n; i += i & -i) for (int j = y; j <= m; j += j & -j) bit[i][j] += val; - Truy vấn tổng trong vùng hình chữ nhật từ \((x_1, y_1)\) đến \((x_2, y_2)\) được tính qua công thức bao hàm loại trừ 2D (Inclusion-Exclusion Principle): \[\text{Sum} = \text{Query}(x_2, y_2) - \text{Query}(x_1 - 1, y_2) - \text{Query}(x_2, y_1 - 1) + \text{Query}(x_1 - 1, y_1 - 1)\]
Độ phức tạp thời gian: \(O(\log N \cdot \log M)\) mỗi thao tác.
Mã nguồn C++ mẫu
#include <bits/stdc++.h>
using namespace std;
int n, m, q;
vector<vector<long long>> bit;
void update(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;
}
}
}
long long query(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;
}
int main(){
ios_base::sync_with_stdio(false); cin.tie(NULL);
if (!(cin >> n >> m >> q)) return 0;
bit.assign(n + 1, vector<long long>(m + 1, 0));
while (q--) {
int t; cin >> t;
if (t == 1) {
int x, y; long long val; cin >> x >> y >> val;
update(x, y, val);
} else {
int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
cout << query(x2, y2) - query(x1 - 1, y2) - query(x2, y1 - 1) + query(x1 - 1, y1 - 1) << "\n";
}
}
}
Nhận xét