Professional Documents
Culture Documents
Contents
Bài toán
Định nghĩa BIT
Thao tác truy xuất
Thao tác cập nhật
Một số bài tập áp dụng (và code giải)
Fenwick Tree, hay còn gọi là cây chỉ số nhị phân (Binary Indexed Tree - BIT), là một cấu
trúc dữ liệu tối ưu cho việc cập nhật giá trị một phần tử và tìm tổng, min/max giữa 2 vị
trí bất kì trong mảng. Độ phức tạp cho mỗi lần cập nhật, truy xuất
là O(logN)O(logN) với N là độ dài dãy cần quản lý. Ngoài thao tác tính tổng, tìm
min/max thì BIT còn có thể sử dụng được cho nhiều thao thác khác nữa.
BIT là một cây, tuy nhiên trong phạm vi bài viết này sẽ không đề cập tới khái niệm gốc
hoặc chứng minh tính đúng đắn của nó, mà chỉ dừng lại ở mức kiến thức đủ để cài đặt
và sử dụng trong thực tế.
Bài toán
Cho dãy số A có N phần tử, giá trị ban đầu của các phần tử bằng 0. Có 2 loại truy vấn
cần thực hiện:
Nếu sử dụng cách tính tổng như bình thường thì thao tác cập nhật có độ phức tạp
là O(1)O(1), còn thao tác tính tổng có độ phức tạp O(N)O(N).
Nếu sử dụng BIT cho bài này thì cả 2 thao tác có chung độ phức tạp
là O(logN)O(logN).
i & (-i) sẽ trả về bit đầu tiên khác 0 của i, ví dụ i=20i=20, có biểu diễn nhị phân
là 1010010100, thì i & (-i) sẽ có biểu diễn nhị phân là 100100, tức là 20 & (-20) = 4.
1 2 3 4 5 6 7 8 9 10
A 3 2 1 5 3 6 2 0 7 1
F 3 5 1 11 3 9 2 22 7 8
result = 0
while i >= 1:
result = result + F[i]
i = i - (i & -i)
Có thể thấy, sau mỗi lần lặp thì một bit 1 trong ii sẽ bị loại bỏ, vì thế số lần lặp là số
lượng bit 1 của ii, dẫn đến độ phức tạp là O(logN)O(logN).
Cách trên cho phép tính tổng từ đầu dãy đến A(i)A(i), nếu muốn tính tổng trên một
đoạn từ A(j)A(j) đến A(i)A(i) thì phải thay đổi thao tác trên một ít:
result = 0
while i >= j:
if i - (i & -i) >= j:
result = result + F[i]
i = i - (i & -i)
else:
result = result + A[i]
i = i - 1
while i <= n:
F[i] = F[i] + 1
i = i + (i & -i)
Dữ liệu
Dòng đầu ghi số nguyên dương N.
N dòng sau mỗi dòng ghi một số ai ( 1 ≤ i ≤ N ).
Kết qủa
Ghi trên một dòng số M duy nhất là số nghịch thế.
Giới hạn
1 ≤ N ≤ 60000
1 ≤ ai ≤ 60000
Ví dụ
Dữ liệu:
3
3
1
2
Kết qủa
2
Gọi C[x]C[x] là số lượng giá trị xx đã xuất hiện. Duyệt các phần tử từ đầu dãy đến cuối
dãy, mối lần duyệt ta tính tổng từ C[x+1]C[x+1] đến cuối mảng CC rồi thêm vào kết
quả, sau đó tăng C[x]C[x] (xx là phần tử đang xét).
Để AC cần sử dụng cấu trúc Fenwick Tree để giảm độ phức tạp của phương pháp trên
xuống còn O(NlogC)O(NlogC).
Lưu ý là ta cần tính tổng từ một vị trí đến cuỗi dãy, ngược lại với phiên bản trong bài
viết trên.
#include <iostream>
#include <vector>
using namespace std;
struct Fenwick {
int n;
vector<LL> f;
Fenwick(int n): n(n), f(n+1, 0) {}
void set(int i) {
for (; i>=1; i -= i&(-i)) f[i]++;
}
LL get(int i) {
LL result = 0;
for (; i<=n; i += i&(-i)) result += f[i];
return result;
}
};
int main() {
ios::sync_with_stdio(false); cin.tie(0);
return 0;
}
NKLINEUP - Xếp hàng
Hàng ngày khi lấy sữa, N con bò của bác John (1 ≤ N ≤ 50000) luôn xếp hàng theo thứ tự không
đổi. Một hôm bác John quyết định tổ chức một trò chơi cho một số con bò. Để đơn giản, bác John
sẽ chọn ra một đoạn liên tiếp các con bò để tham dự trò chơi. Tuy nhiên để trò chơi diễn ra vui vẻ,
các con bò phải không quá chênh lệch về chiều cao.
Bác John đã chuẩn bị một danh sách gồm Q (1 ≤ Q ≤ 200000) đoạn các con bò và chiều cao của
chúng (trong phạm vi [1, 1000000]). Với mỗi đoạn, bác John muốn xác định chênh lệch chiều cao
giữa con bò thấp nhất và cao nhất. Bạn hãy giúp bác John thực hiện công việc này!
Dữ liệu
Dòng đầu tiên chứa 2 số nguyên N và Q.
Dòng thứ i trong số N dòng sau chứa 1 số nguyên duy nhất, là độ cao của con bò thứ i.
Dòng thứ i trong số Q trong tiếp theo chứa 2 số nguyên A, B (1 ≤ A ≤ B ≤ N), cho biết đoạn
các con bò từ A đến B.
Kết qủa
Gồm Q dòng, mỗi dòng chứa 1 số nguyên, là chênh lệch chiều cao giữa con bò thấp nhất và cao
nhất thuộc đoạn tương ứng.
Ví dụ
Dữ liệu:
6 3
1
7
3
4
2
5
1 5
4 6
2 2
Kết qủa
6
3
0
Submit solution!
#include <iostream>
#include <vector>
using namespace std;
struct Fenwick {
int n, init;
vector<int> f, a;
func update;
int main() {
ios::sync_with_stdio(false); cin.tie(0);
while (q--) {
int l, r; cin >> l >> r;
cout << fmax.get(l, r) - fmin.get(l, r) << endl;
}
return 0;
}
7. Tính tổng các giá trị được tích luỹ từ nút i đến nút j (kể cả tích luỹ trên nút i và trên
nút j)như thế nào? (trả lời yêu cầu 2).
Rõ ràng tổng các giá trị được tích luỹ từ nút i đến nút j (i<=j) bằng tổng tích luỹ đến nút j trừ đi các
giá trị đã tích luỹ trên các nút trước i (đó là tổng các giá trị được tích luỹ trên nút i-1). Ta có hàm tính
tổng này như sau:
1. T i j là đề nghị quay ngược các tấm bìa từ chỉ số i đến chỉ số j (kể cả i và j) tấm nào đang úp
thì thành ngửa, tấm nào đang ngửa thì úp xuống
2. Q i yêu cầu trả lời là 0 nếu tấm bìa i là úp, ngược lại trả lời là 1 nếu tấm bìa i ngửa.
Input. Tệp gồm nhiều dòng, mỗi dòng là một chất vấn thuộc hai loại trên
Output. Gồm một số dòng, mỗi dòng là một trả lời cho chất vấn Q(i), theo đúng thứ tự chất vấn
trong input.
Ví dụ.
input output
T 1 4T 3 6T 2 5Q 1Q 2 10111
Q3 1
Q4 0
T23 1
Q1 0
Q2 1
Q3 0
Q4
Q5
Q6
Q7
Hướng dẫn. Ban đầu các bìa chưa chịu tác động nào nên coi tần số các nút đều bằng 0. Giá trị tích
luỹ tổng các tần số lên các nút cũng bằng 0 tại mọi nút. Thực hiện chất vấn T(i, j): với mỗi nút k nằm
giữa i và j (kể cả i và j) cần cập nhật tree[k] thêm 1 (vì thêm một lần lật quân k). Câu trả lời cho Q(i)
chính là f[i] mod 2 (vì ban đầu i úp, sau số chẵn lần lật thì vẫn úp). Lời giải cho mỗi câu chất vấn
được thực hiện trong thời gian O(logN).
II) Cấu trúc Binary indexed trees 2-D.
Cấu trúc Binary Indexed Trees tổ chức trên mảng một chiều có thể tổng quát hoá thành cấu trúc
Binary Indexed Trees trên mảng nhiều chiều. Sau đây là cấu trúc Binary Indexed Trees trên mảng hai
chiều (2-Dimensions).
Xét mảng hai chiều kích thước A[1..M, 1..N] (M dòng, N cột), giả sử đánh số hàng từ 1 đến M và
đánh số cột từ 1 đến N. Ta xây dựng tập S1 gồm M cây BIT (Binary indexed trees), mỗi BIT dùng xử
lý thông tin một dòng của mảng A (mỗi BIT có N nút, mỗi nút i gán giá trị là tổng tích luỹ từ ô 1 đến
ô i của dòng). Đồng thời xây dựng tập S2 gồm N cây BIT: cây BIT thứ nhất của S2 quản lý các nút
thứ nhất của M cây BIT thuộc S1, cây BIT thứ hai của S2 quản lý các nút thứ hai của M cây BIT
thuộc S1, …, cây BIT thứ N của S2 quản lý các nút thứ N của M cây BIT thuộc S1.
1. Cập nhật nút (x;y)
Khi cần cập nhật thêm giá trị amount vào ô (x;y) thuộc dòng y cột x của mảng A ta cập nhật lại các ô
là tiền bối của (x;y) như sau:
1. a) Trên cây BIT thứ y của tập S1, tìm các nút xtiền bối của nút x
2. b) Với mỗi cây BIT thứ xtiền bối của tập S2, tìm các nút ytiền bối của y.
Cập nhật ô (xtiền bối; ytiền bối).
void update (int x, int y, int amount){
int ix, jy;
for( ix=x; ix < maxM; ix += (ix & (-ix)) ) // Tìm đến các tiền bối của x
for( jy=y; jy < maxN; jy += (jy & (-jy)) // Tìm đến các tiền bối của y
A[jy][ix] += amount; // Cập nhật các ô tiền bối của ô (x,y) dòng y, cột x
}
Hai hình sau đây lần lượt minh hoạ cập nhật ô (1; 1) và ô (2; 5) dòng 5, cột 2
Chú ý : Trong mỗi cây BIT, nút 8 là cha của nút 4, 6 và 7 ; nút 4 là cha của nút 2 và 3; nút 2 là cha
của nút 1; nút 6 là cha của nút 5
2. Tính tổng các ô trong hình chữ nhật (x1, y1,x2,y2)
Để trả về tổng các ô trong hình chữ nhật có góc trái-dưới là ô (x 1; y1) và góc phải-trên là ô (x2; y2) ta
thực hiện quá trình ngược lại quá trình cập nhật:
1. a) Trên cây BIT thứ x2 của S1, tìm các jy là các hậu duệ của y2, jy>y1
2. b) Trên cây BIT thứ jy của S2, tìm các ix là các hậu duệ của x 2, ix>x1
3. c) Giảm tổng tích luỹ trên (x2; y2) một lượng là tổng tích luỹ trên các ô hậu duệ (ix; jy).
Hàm tính tổng các ô trong hình chữ nhật có góc trái-dưới là ô (x 1; y1) và góc phải-trên là ô (x2; y2)
giới thiệu trong ví dụ dưới đây:
3. Ví dụ. Giải bài tập MATSUM – Matrix Summation
Cho ma trận A (N × N) các số. BuggyD là nhà phân tích ma trận và anh ấy muốn biết tổng các số
trong một ma trận con bất kỳ của A, do đó muốn có một hệ thống cho kết quả ứng với các truy vấn
này. Hệ thống cũng đáp ứng ngay cả khi ma trận biến động chấp nhận các giá trị mới trên các ô của
ma trận. Giả sử ban đầu các ô của ma trận đều bằng 0. Bạn hãy xây dựng hệ thống cho BuggyD. Đọc
khuôn dạng input cho chi tiết dưới đây
Input
Dòng đầu tiên của input chứa số nguyên t, là số các test. Tiếp theo là t test. Dòng đầu của mỗi test
chứa số nguyên N (1 <= N <= 1024), là chiều rộng ma trận. Tiếp theo là danh sách các lệnh, mỗi
lệnh có một trong 3 dạng sau:
SET x y num – Đặt giá trị tại ô (x, y) (0 <= x, y < N) thành num
SUM x1 y1 x2 y2 – Tìm và xuất ra tổng các số trong hình chữ nhật từ ô (x1, y1) đến ô (x2, y2), kể cả
chúng, x1 <= x2 và y1 <= y2, và kết quả không vượt quá số nguyên 32 bit.
Output
Với mỗi test, output trên một dòng cho mỗi lệnh SUM. Để một dòng trống sau mỗi test.
Ví dụ
Input:
1
4
SET 0 0 1
SUM 0 0 3 3
SET 2 2 12
SUM 2 2 2 2
SUM 2 2 3 3
SUM 0 0 2 2
END
Output
1
12
12
13
Chương trình.
#include <iostream>
#include <fstream>
using namespace std;
#define LL long long
LL tree[1050][1050];
void update(int x,int y,int val,int MAX){
while(x<=MAX) {
int ty = y;
while(ty <= MAX) {
tree[x][ty] += val;
ty += (ty & -ty);
}
x += (x & -x);
}
}
LL read(int x,int y){ //Tổng các số trong hcn từ (0,0) đến (x-1, y-1)
LL sum = 0;
while( x ) {
int ty = y;
while( ty ) {
sum += tree[x][ty];
ty -= (ty & -ty);
}
x -= (x & -x);
}
return sum;
}
int main(){
int t;
freopen(“matsum.inp”,”r”,stdin);
freopen(“matsum.out”,”w”,stdout);
scanf(“%d”,&t);
while(t–) {
int n;
scanf(“%d”,&n);
memset(tree,0,sizeof tree);
while(1) {
char s[10];
scanf(“%s”,s);
if(s[1] == ‘E’){ //SET
int x,y,val;
scanf(” %d%d%d”,&x,&y,&val);//Yêu cầu đặt giá trị tại ô (x,y)thành val
//Giá trị đã có tại ô (x,y)
LL p_val=read(x+1,y+1)+read(x,y)-read(x+1,y)-read(x,y+1);
update(x+1,y+1,val-p_val,n+9); // Thêm val-p_val vào ô (x,y)
}
else if(s[1] == ‘U’){ //SUM
LL sum = 0;
int x1,y1,x,y;
scanf(” %d%d%d%d”,&x,&y,&x1,&y1); //Xuất ra tổngtrong hcn(x,y,x1,y1)
sum=read(x1+1,y1+1)+read(x,y)-read(x,y1+1)-read(x1+1,y);
printf(“%lld\n”,sum);
}
else{
//printf(“\n”);
break;
}
}
printf(“\n”);
}
return 0;
}
Ghi chú.
Hãy viết chương trình nhận các báo cáo đó và trả lời được các yêu cầu về tổng số điện thoại di động
đang hoạt động trong một vùng không gian hình vuông cho trước. Hãy viết chương trình tiếp nhận
các báo cáo này và trả lời các yêu câu cho biết tổng số điện thoại đang hoạt động trong một hình chữ
nhật của vùng.
Input: Dữ liệu vào đọc từ tệp input chuẩn như các số nguyên và trả lời các chất vấn ghi vào output
chuẩn như các số nguyên. Dữ liệu vào đã được mã hoá như sau: Mỗi dữ liệu vào trên một dòng riêng
gồm một số nguyên chỉ dẫn và một số tham số nguyên như bảng sau:
Số nguyên chỉ Các số nguyên Ý nghĩa
dẫn tham số
0 S Khởi trị ma trận kích thước SS. Chỉ dẫn này chỉ cho một lần
và là chỉ dẫn đầu tiên
2 LBRT Hỏi tổng số điện thoại đang hoạt động trong các trạm (x,y)
với L≤x≤R, B≤y≤T.
3 Dừng chương trình. Chỉ dẫn này chỉ cho một lần và là chỉ
dẫn cuối cùng.
Các giá trị luôn trong phạm vi, không cần kiểm tra. Riêng A có thể âm, khi đó không giảm giá trị
trạm xuồng dưới 0. Các chỉ số bắt đầu từ 0 ví dụ bảng 44 thì có 0 x3, 0y3. Chương trình của bạn sẽ
không trả lời cho bất kì chỉ dẫn nào khác 2. Nếu chỉ dẫn là 2 thì chương trình của bạn cần trả lời chất
vấn bằng ghi trả lời trên đúng một dòng chứa số nguyên trên tệp output.
20022 Chất vấn tổng trong hình chữ nhật gồm các ô (x,y) mà
0≤x≤2; 0≤y≤2
21123 Chất vấn tổng trong hình chữ nhật gồm các ô (x,y) mà
1≤x≤2; 1≤y≤3
Hạn chế:
Giá trị mỗi ô là V tại bất kì thời điểm nào V 0 ≤ V ≤ 215-1 (=32767)
Lượng cập nhật A -215 ≤ A ≤ 215-1
Hướng dẫn. Xây dựng cây BIT_2D. Lưu ý, trong các cây BIT thuộc tập S1 và tập S2, các nút được
đánh số từ 1 đến N, nhưng trong bài toán này dòng và cột của mảng đánh số từ 0.
Advertisements
Report this ad
Report this ad
Chia sẻ:
Twitter
Facebook
Google
Trả lời
Thư viện
SỔ BLOG
H B T N S B C
« Th11
1 2
H B T N S B C
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
1. T i j là đề nghị quay ngược các tấm bìa từ chỉ số i đến chỉ số j (kể cả i và j) tấm nào đang úp
thì thành ngửa, tấm nào đang ngửa thì úp xuống
2. Q i yêu cầu trả lời là 0 nếu tấm bìa i là úp, ngược lại trả lời là 1 nếu tấm bìa i ngửa.
Input. Tệp gồm nhiều dòng, mỗi dòng là một chất vấn thuộc hai loại trên
Output. Gồm một số dòng, mỗi dòng là một trả lời cho chất vấn Q(i), theo đúng thứ tự chất
vấn trong input.
Ví dụ.
input output
T 1 4T 3 6T 2 5Q 1Q 2 10111
Q3 1
Q4 0
T23 1
Q1 0
Q2 1
Q3 0
Q4
Q5
Q6
Q7
Hướng dẫn. Ban đầu các bìa chưa chịu tác động nào nên coi tần số các nút đều bằng 0. Giá trị
tích luỹ tổng các tần số lên các nút cũng bằng 0 tại mọi nút. Thực hiện chất vấn T(i, j): với mỗi
nút k nằm giữa i và j (kể cả i và j) cần cập nhật tree[k] thêm 1 (vì thêm một lần lật quân k).
Câu trả lời cho Q(i) chính là f[i] mod 2 (vì ban đầu i úp, sau số chẵn lần lật thì vẫn úp). Lời
giải cho mỗi câu chất vấn được thực hiện trong thời gian O(logN).
II) Cấu trúc Binary indexed trees 2-D.
Cấu trúc Binary Indexed Trees tổ chức trên mảng một chiều có thể tổng quát hoá thành cấu
trúc Binary Indexed Trees trên mảng nhiều chiều. Sau đây là cấu trúc Binary Indexed Trees
trên mảng hai chiều (2-Dimensions).
Xét mảng hai chiều kích thước A[1..M, 1..N] (M dòng, N cột), giả sử đánh số hàng từ 1 đến M
và đánh số cột từ 1 đến N. Ta xây dựng tập S1 gồm M cây BIT (Binary indexed trees), mỗi BIT
dùng xử lý thông tin một dòng của mảng A (mỗi BIT có N nút, mỗi nút i gán giá trị là tổng
tích luỹ từ ô 1 đến ô i của dòng). Đồng thời xây dựng tập S2 gồm N cây BIT: cây BIT thứ nhất
của S2 quản lý các nút thứ nhất của M cây BIT thuộc S1, cây BIT thứ hai của S2 quản lý các
nút thứ hai của M cây BIT thuộc S1, …, cây BIT thứ N của S2 quản lý các nút thứ N của M cây
BIT thuộc S1.
Chú ý : Trong mỗi cây BIT, nút 8 là cha của nút 4, 6 và 7 ; nút 4 là cha của nút 2 và 3; nút 2 là cha
của nút 1; nút 6 là cha của nút 5
2. Tính tổng các ô trong hình chữ nhật (x1, y1,x2,y2)
Để trả về tổng các ô trong hình chữ nhật có góc trái-dưới là ô (x1; y1) và góc phải-trên là ô (x2;
y2) ta thực hiện quá trình ngược lại quá trình cập nhật:
1. a) Trên cây BIT thứ x2 của S1, tìm các jy là các hậu duệ của y2, jy>y1
2. b) Trên cây BIT thứ jy của S2, tìm các ix là các hậu duệ của x 2, ix>x1
3. c) Giảm tổng tích luỹ trên (x2; y2) một lượng là tổng tích luỹ trên các ô hậu duệ (ix; jy).
Hàm tính tổng các ô trong hình chữ nhật có góc trái-dưới là ô (x1; y1) và góc phải-trên là ô
(x2; y2) giới thiệu trong ví dụ dưới đây:
3. Ví dụ. Giải bài tập MATSUM – Matrix Summation
Cho ma trận A (N × N) các số. BuggyD là nhà phân tích ma trận và anh ấy muốn biết tổng các
số trong một ma trận con bất kỳ của A, do đó muốn có một hệ thống cho kết quả ứng với các
truy vấn này. Hệ thống cũng đáp ứng ngay cả khi ma trận biến động chấp nhận các giá trị mới
trên các ô của ma trận. Giả sử ban đầu các ô của ma trận đều bằng 0. Bạn hãy xây dựng hệ
thống cho BuggyD. Đọc khuôn dạng input cho chi tiết dưới đây
Input
Dòng đầu tiên của input chứa số nguyên t, là số các test. Tiếp theo là t test. Dòng đầu của mỗi
test chứa số nguyên N (1 <= N <= 1024), là chiều rộng ma trận. Tiếp theo là danh sách các
lệnh, mỗi lệnh có một trong 3 dạng sau:
SET x y num – Đặt giá trị tại ô (x, y) (0 <= x, y < N) thành num
SUM x1 y1 x2 y2 – Tìm và xuất ra tổng các số trong hình chữ nhật từ ô (x1, y1) đến ô (x2, y2),
kể cả chúng, x1 <= x2 và y1 <= y2, và kết quả không vượt quá số nguyên 32 bit.
Output
Với mỗi test, output trên một dòng cho mỗi lệnh SUM. Để một dòng trống sau mỗi test.
Ví dụ
Input:
1
4
SET 0 0 1
SUM 0 0 3 3
SET 2 2 12
SUM 2 2 2 2
SUM 2 2 3 3
SUM 0 0 2 2
END
Output
1
12
12
13
Chương trình.
#include <iostream>
#include <fstream>
using namespace std;
#define LL long long
LL tree[1050][1050];
void update(int x,int y,int val,int MAX){
while(x<=MAX) {
int ty = y;
while(ty <= MAX) {
tree[x][ty] += val;
ty += (ty & -ty);
}
x += (x & -x);
}
}
LL read(int x,int y){ //Tổng các số trong hcn từ (0,0) đến (x-1, y-1)
LL sum = 0;
while( x ) {
int ty = y;
while( ty ) {
sum += tree[x][ty];
ty -= (ty & -ty);
}
x -= (x & -x);
}
return sum;
}
int main(){
int t;
freopen(“matsum.inp”,”r”,stdin);
freopen(“matsum.out”,”w”,stdout);
scanf(“%d”,&t);
while(t–) {
int n;
scanf(“%d”,&n);
memset(tree,0,sizeof tree);
while(1) {
char s[10];
scanf(“%s”,s);
if(s[1] == ‘E’){ //SET
int x,y,val;
scanf(” %d%d%d”,&x,&y,&val);//Yêu cầu đặt giá trị tại ô (x,y)thành val
//Giá trị đã có tại ô (x,y)
LL p_val=read(x+1,y+1)+read(x,y)-read(x+1,y)-read(x,y+1);
update(x+1,y+1,val-p_val,n+9); // Thêm val-p_val vào ô (x,y)
}
else if(s[1] == ‘U’){ //SUM
LL sum = 0;
int x1,y1,x,y;
scanf(” %d%d%d%d”,&x,&y,&x1,&y1); //Xuất ra tổngtrong hcn(x,y,x1,y1)
sum=read(x1+1,y1+1)+read(x,y)-read(x,y1+1)-read(x1+1,y);
printf(“%lld\n”,sum);
}
else{
//printf(“\n”);
break;
}
}
printf(“\n”);
}
return 0;
}
Ghi chú.
Hãy viết chương trình nhận các báo cáo đó và trả lời được các yêu cầu về tổng số điện thoại di
động đang hoạt động trong một vùng không gian hình vuông cho trước. Hãy viết chương
trình tiếp nhận các báo cáo này và trả lời các yêu câu cho biết tổng số điện thoại đang hoạt
động trong một hình chữ nhật của vùng.
Input: Dữ liệu vào đọc từ tệp input chuẩn như các số nguyên và trả lời các chất vấn ghi vào
output chuẩn như các số nguyên. Dữ liệu vào đã được mã hoá như sau: Mỗi dữ liệu vào trên
một dòng riêng gồm một số nguyên chỉ dẫn và một số tham số nguyên như bảng sau:
Số nguyên chỉ Các số nguyên Ý nghĩa
dẫn tham số
0 S Khởi trị ma trận kích thước SS. Chỉ dẫn này chỉ cho một lần
và là chỉ dẫn đầu tiên
2 LBRT Hỏi tổng số điện thoại đang hoạt động trong các trạm (x,y)
với L≤x≤R, B≤y≤T.
3 Dừng chương trình. Chỉ dẫn này chỉ cho một lần và là chỉ
dẫn cuối cùng.
Các giá trị luôn trong phạm vi, không cần kiểm tra. Riêng A có thể âm, khi đó không giảm giá
trị trạm xuồng dưới 0. Các chỉ số bắt đầu từ 0 ví dụ bảng 44 thì có 0 x3, 0y3. Chương trình
của bạn sẽ không trả lời cho bất kì chỉ dẫn nào khác 2. Nếu chỉ dẫn là 2 thì chương trình của
bạn cần trả lời chất vấn bằng ghi trả lời trên đúng một dòng chứa số nguyên trên tệp output.
20022 Chất vấn tổng trong hình chữ nhật gồm các ô (x,y) mà
0≤x≤2; 0≤y≤2
Hạn chế:
Giá trị mỗi ô là V tại bất kì thời điểm nào V 0 ≤ V ≤ 215-1 (=32767)
Hướng dẫn. Xây dựng cây BIT_2D. Lưu ý, trong các cây BIT thuộc tập S1 và tập S2, các nút
được đánh số từ 1 đến N, nhưng trong bài toán này dòng và cột của mảng đánh số từ 0.