Cập nhật phạm vi + truy vấn phạm vi với các cây được lập chỉ mục nhị phân


10

Tôi đang cố gắng hiểu làm thế nào các cây được lập chỉ mục nhị phân (cây fenwick) có thể được sửa đổi để xử lý cả truy vấn phạm vi và cập nhật phạm vi.

Tôi tìm thấy các nguồn sau đây:

http://kartikkukreja.wordpress.com/2013/12/02/range-updates-with-bit-fenwick-tree/ http://programmingcontests.quora.com/Tutorial-Range-Updates-in-Fenwick-Tree http : //apps.topcoder.com/forums/? module = Chủ đề & threadID = 756271 & start = 0 & mc = 4 # 1579597

Nhưng ngay cả sau khi đọc qua tất cả chúng, tôi không thể hiểu mục đích của cây được lập chỉ mục nhị phân thứ hai là gì hoặc nó làm gì.

Ai đó có thể vui lòng giải thích cho tôi làm thế nào cây được lập chỉ mục nhị phân được sửa đổi để xử lý những cái này?

Câu trả lời:


9

Giả sử bạn có một mảng trống:

0  0  0  0  0  0  0  0  0  0  (array)
0  0  0  0  0  0  0  0  0  0  (cumulative sums)

Và bạn muốn thực hiện cập nhật phạm vi từ +5 đến [3..7]:

0  0  0  5  5  5  5  5  0  0  (array)
0  0  0  5 10 15 20 25 25 25  (desired cumulative sums)

Làm thế nào bạn có thể lưu trữ các khoản tiền tích lũy mong muốn bằng cách sử dụng 2 cây được lập chỉ mục nhị phân?

Bí quyết là sử dụng hai cây được lập chỉ mục nhị phân là BIT1 và BIT2, trong đó tổng tích lũy được tính từ nội dung của chúng. Trong ví dụ này, đây là những gì chúng tôi sẽ lưu trữ trong hai cây:

0   0   0   5   5   5   5   5   0   0  (BIT1)
0   0   0  10  10  10  10  10 -25 -25  (BIT2)

Để tìm sum[i], bạn tính toán này:

sum[i] = BIT1[i] * i - BIT2[i]

Ví dụ:

sum[2] = 0*2 - 0 = 0
sum[3] = 5*3 - 10 = 5
sum[4] = 5*4 - 10 = 10
...
sum[7] = 5*7 - 10 = 25
sum[8] = 0*8 - (-25) = 25
sum[9] = 0*9 - (-25) = 25

Để đạt được các giá trị BIT1 và BIT2 mong muốn cho bản cập nhật phạm vi trước đó, chúng tôi thực hiện 3 cập nhật phạm vi:

  • Chúng tôi cần thực hiện cập nhật phạm vi +5 cho các chỉ số 3..7 cho BIT1.

  • Chúng tôi cần thực hiện cập nhật phạm vi +10 cho các chỉ số 3..7 cho BIT2.

  • Chúng ta cần thực hiện cập nhật phạm vi từ -25 đến các chỉ số 8..9 cho BIT2.

Bây giờ hãy thực hiện một chuyển đổi nữa. Thay vì lưu trữ các giá trị được hiển thị ở trên cho BIT1 và BIT2, chúng tôi thực sự lưu trữ các khoản tiền tích lũy của chúng. Điều này cho phép chúng tôi thực hiện 3 cập nhật phạm vi ở trên bằng cách thực hiện 4 cập nhật cho các khoản tiền tích lũy:

BIT1sum[3] += 5
BIT1sum[8] -= 5
BIT2sum[3] += 10
BIT2sum[8] -= 35

Nói chung, thuật toán để thêm giá trị v vào phạm vi [i..j] sẽ là:

BIT1sum[i]   += v
BIT1sum[j+1] -= v
BIT2sum[i]   += v * (i-1)
BIT2sum[j+1] -= v * j

trong đó cú pháp + = và - = chỉ đơn giản là cập nhật cấu trúc dữ liệu tổng tích lũy BIT với giá trị dương hoặc âm tại chỉ mục đó. Lưu ý rằng khi bạn cập nhật tổng tích lũy BIT tại một chỉ mục, nó hoàn toàn ảnh hưởng đến tất cả các chỉ số ở bên phải của chỉ mục đó. Ví dụ:

0 0 0 0 0 0 0 0 0 0 (original)

BITsum[3] += 5

0 0 0 5 5 5 5 5 5 5 (after updating [3])

BITsum[8] -= 5

0 0 0 5 5 5 5 5 0 0 (after updating [8])

Ôi(đăng nhậpn)


Động lực ban đầu của bạn khi tạo BIT2 là gì và sau đó có sum[i] = BIT1[i] * i - BIT2[i]gì? Nó có vẻ hoạt động nhưng có vẻ rất độc đoán ... cái nhìn sâu sắc nào cho phép bạn đến với điều này?
1110101001

3
Vâng, tôi đã không phát minh ra thuật toán này. Tôi đọc nó giống như bạn đã làm. Nhưng một điều cần chú ý là khi bạn thêm một bản cập nhật phạm vi, các khoản tiền tích lũy của bạn sẽ trở thành một chuỗi tăng dần (5, 10, 15, 20, ...). BIT không lưu trữ các chuỗi tăng như thế. Nhưng nếu bạn lưu trữ một hằng số (5) trong BIT và nhân giá trị BIT với chỉ số, bạn sẽ có được một chuỗi tăng giống như những gì bạn muốn. Tuy nhiên, bạn cần sửa chữa phần đầu và phần cuối của chuỗi. Đó là những gì cây thứ hai dành cho.
JS1

Nhìn chung, nhưng tôi thấy khó hiểu khi bạn viết "Thay vì lưu trữ các giá trị được hiển thị ở trên cho BIT1 và BIT2, chúng tôi thực sự lưu trữ các khoản tiền tích lũy của họ" - Tôi sẽ nói rằng bạn thực sự đang làm ngược lại, tức là lưu trữ deltas .
j_random_hacker
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.