1. 程式人生 > >小結:區間處理和統計與高階資料結構

小結:區間處理和統計與高階資料結構

區間處理和統計是OI中一類重要的題型,而這類題目通常需要用高階資料結構維護,這裡就先總結一下本人學習過的可以用於區間處理和統計的高階資料結構。

注意,本人此處不提供各個資料結構的詳細介紹或教學,詳細教學請自行搜尋。

一、線段樹

線段樹可以說是區間處理和統計問題的基礎,它支援靜態區間的維護,支援區間修改和區間詢問。但維護的資訊要求有可區間合併性,就是指一個區間的資訊可以由它分割成的兩個區間的資訊合併得到,比如線段樹可以維護區間和,區間極值,最大子段和,最長連續段等等。

由於線段樹的特殊性質,也可以用很優美的O(logn)複雜度解決一些奇怪的問題,例如POJ3667中要求找出位於最左端的連續若干個0,這就可以用線段樹的性質進行二分查詢。

線段樹能解決的經典問題有:序列的逆序對數等。

線段樹的一個有用的擴充套件就是二維線段樹,就是在母線段樹(第一維)的每個節點再儲存一棵子線段樹(第二維),從而實現矩陣的維護。線段樹還可以在樹鏈剖分(也被稱為路徑剖分,或基於鏈的樹上分治)中起到維護重鏈的作用,使其可以維護靜態樹結構的路徑資訊和子樹資訊。除此之外,線段樹的可持久化也是一個非常有用的擴充套件,這個後面再談。

二、平衡樹

線段樹之所以是基礎,是因為還有很多其不能解決的問題,例如:要求支援在區間中插入或刪除元素,或者詢問整體第K小的元素,這就使線段樹束手無策了。這時就要請出一個更為靈活的資料結構:平衡樹。平衡樹有多種寫法:SBT,treap,splay等,但多用於區間處理的還是splay(伸展樹)。伸展樹和線段樹最大的不同就是可以支援插入和刪除元素,而且基本上包含了線段樹可以解決的所有問題,是一個非常優秀的資料結構。

伸展樹能解決的經典問題有:查詢整體第K小值,查詢元素排名等。

伸展樹在LCT(Link-Cut Tree)中起到維護偏愛鏈的作用,類似於線段樹在樹鏈剖分中維護重鏈。類比於伸展樹與線段樹,LCT對於樹鏈剖分來說也更靈活了,可以支援動態樹結構的維護,這裡就不展開了。

三、樹狀陣列

樹狀陣列是一個線段樹的精巧替代品,程式碼複雜度低,可以起到維護動態字首和的作用,其維護區間和的方式就是用字首和相減,這也就說明樹狀陣列只能維護有可減性的資訊,例如區間和有可減性,而區間極值沒有可減性(也就是說,不能通過兩個字首極值的操作來求出一個區間的極值),所以樹狀陣列的作用域很小,一般不是不可或缺。

樹狀陣列能解決的經典問題有:方便地維護動態字首和。

四、可持久化線段樹(主席樹)

可持久化線段樹就是線段樹的可持久化版本。什麼叫可持久化?就是支援歷史版本的查詢,例如:詢問第K次修改後的區間和,這時用多棵線段樹儲存歷史版本顯然就硬傷了,而可持久化線段樹就專門解決了這一問題。因為每次修改都不會修改超過logn個節點,所以我們只需每次修改時新開logn個節點就可以了。而一些看起來像線段樹,又不能用線段樹解決的題目,就要考慮是不是可以轉化為對歷史版本的維護和訪問。例如查詢區間第K小,就可以將插入一個元素看成一個單點修改,那麼維護區間內都有哪些數時就可以用後面的版本減去前面的版本得到。是不是很熟悉?是的,這和字首和的思想是差不多的。

可持久化線段樹能解決的經典問題有:線上查詢區間第K小,帶單點修改線上查詢區間第k小,區間中位數,區間眾數等。

至於帶單點修改的線上查詢區間第K小我有寫過,是用樹狀陣列套主席樹,再次證明樹狀陣列維護動態字首和的優越性。

五、莫隊演算法

莫隊演算法只能解決離線的區間查詢問題,但能解決一些以上資料結構都無法解決的一些問題,維護的資訊要求是能在較短的時間內(O(1)~O(logn))由一個區間的資訊轉移到插入或刪除一個元素後區間的資訊。O(n*sqrt(n))的時間複雜度雖然比以上資料結構都差一籌,但是程式碼複雜度較低,且思考難度不大,在考場上時間緊迫的情況下可以考慮採用這種方法。

莫隊演算法能解決的經典問題有:區間眾數等。

我們發現一些主席樹能解決的問題,莫隊演算法也能解決,因為它們的思想本質上都是類似的,只是主席樹中將這個資訊轉移的過程看做單點修改,但如果這個轉移無法看做線段樹上的修改,就是莫隊演算法大顯身手的時候了。

就先總結到這,等以後學到了更多再補充吧~