Persistent Segment Tree
Chủ Tịch Tree (Persistent Segment Tree)
Chủ Tịch Tree, tên đầy đủ là Persistent Segment Tree (Cây phân đoạn bền vững), bạn có thể tham khảo thảo luận trên Zhihu.
Về Functional Segment Tree
Functional Segment Tree (Cây phân đoạn hàm) là cây phân đoạn sử dụng tư tưởng lập trình hàm. Trong tư tưởng lập trình hàm, tính toán máy tính được coi là hàm toán học và tránh các trạng thái hoặc biến có thể thay đổi. Không khó để nhận thấy, Functional Segment Tree là Fully Persistent (bền vững hoàn toàn).
Giới thiệu
Trước tiên hãy xem xét một bài toán: Cho một dãy số nguyên \(a\) gồm \(n\) phần tử, với một khoảng đóng \([l, r]\) bất kỳ, hãy tìm giá trị nhỏ thứ \(k\) trong khoảng đó.
Bạn sẽ giải quyết vấn đề này như thế nào?
Một giải pháp khả thi là: sử dụng Chủ Tịch Tree. Ý tưởng chính của Chủ Tịch Tree là: lưu lại các phiên bản lịch sử mỗi khi thực hiện thao tác chèn, để thuận tiện cho việc truy vấn giá trị nhỏ thứ \(k\) trong khoảng.
Làm thế nào để lưu lại? Một cách đơn giản và "trâu bò" là mỗi lần tạo một cây phân đoạn mới. Nhưng làm vậy thì bộ nhớ sẽ bị tràn mất?
Giải thích
Chúng ta hãy phân tích một chút, mỗi lần thao tác sửa đổi, số lượng điểm bị thay đổi là như nhau.
(Ví dụ như hình bên dưới, sửa đổi nút có giá trị bằng 1 trong khoảng \([1,8]\), các điểm màu đỏ là các điểm bị thay đổi)

Chỉ có \(O(\log{n})\) nút bị thay đổi, tạo thành một chuỗi, tức là số lượng nút bị thay đổi mỗi lần = chiều cao của cây. Lưu ý rằng Chủ Tịch Tree không thể sử dụng phương pháp lưu trữ kiểu heap (nghĩa là không thể dùng \(x\times 2\), \(x\times 2+1\) để biểu diễn con trái và con phải), mà phải sử dụng cấp phát động (dynamic node creation) và lưu lại chỉ số con trái, con phải của mỗi nút. Vì vậy, chúng ta chỉ cần lưu lại nút gốc tại thời điểm chèn mỗi số, dựa trên việc ghi nhận con trái và con phải, là có thể thực hiện được tính bền vững (persistence).
Chúng ta hãy đơn giản hóa bài toán: mỗi lần tìm giá trị nhỏ thứ \(k\) trong khoảng \([1,r]\). Làm thế nào? Chỉ cần tìm phiên bản nút gốc khi chèn đến \(r\), sau đó sử dụng cây phân đoạn giá trị (Value Segment Tree) thông thường để giải quyết.
Điều này chắc mọi người đều hiểu, quay lại bài toán ban đầu - tìm giá trị nhỏ thứ \(k\) trong khoảng \([l,r]\). Ở đây chúng ta liên hệ đến một kiến thức khác: Tiền tố (Prefix Sum). Công cụ nhỏ bé này sử dụng khéo léo tính chất của phép trừ trên khoảng, thông qua việc tiền xử lý để đạt được việc trả lời mỗi truy vấn trong \(O(1)\).
Chúng ta có thể nhận thấy, thông tin thống kê của Chủ Tịch Tree cũng thỏa mãn tính chất này. Vì vậy... nếu cần lấy thông tin thống kê của khoảng \([l,r]\), chỉ cần lấy thông tin của \([1,r]\) trừ đi thông tin của \([1,l - 1]\).
Đến đây, vấn đề đã được giải quyết!
Về vấn đề không gian, chúng ta hãy phân tích: do chúng ta cấp phát động, nên một cây phân đoạn ban đầu chỉ có \(2n-1\) nút. Sau đó, có \(n\) lần sửa đổi, mỗi lần tăng tối đa \(\lceil\log_2{n}\rceil+1\) nút. Do đó, trong trường hợp xấu nhất, tổng số nút sau \(n\) lần sửa đổi sẽ đạt \(2n-1+n(\lceil\log_2{n}\rceil+1)\). Với bài toán này \(n \leq 10^5\), một lần sửa đổi tăng tối đa \(\lceil\log_2{10^5}\rceil+1 = 18\) nút, vậy tổng số nút sau \(n\) lần sửa đổi là \(2\times 10^5-1+18\times 10^5\), bỏ qua \(-1\), xấp xỉ \(20\times 10^5\).
Cuối cùng là một lời khuyên: đừng keo kiệt không gian (hầu hết các bài toán giới hạn không gian đều khá thoải mái, nên thường không phải lo lắng về việc vượt quá giới hạn không gian)! Hãy mạnh dạn cấp phát \(2^5\times 10^5\), gần gấp đôi không gian gốc (tức là n << 5).
Cài đặt
1 2 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | |
Mở rộng: DSU Bền vững dựa trên Chủ Tịch Tree
Chủ Tịch Tree là một cách thuận tiện để thực hiện Disjoint Set Union (DSU) bền vững (Persistent DSU). Dưới đây là một ví dụ về việc thực hiện DSU bền vững dựa trên Chủ Tịch Tree.
1 2 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | |
Tham khảo
https://en.wikipedia.org/wiki/Persistent_data_structure
https://www.cnblogs.com/zinthos/p/3899565.html
Last updated on this page:, Update history
Found an error? Want to help improve? Edit this page on GitHub!
Contributors to this page:OI-wiki
All content on this page is provided under the terms of the CC BY-SA 4.0 and SATA license, additional terms may apply