主席樹明明是個很棒的東西,可惜網上卻很難找到很好的模板/講解
包括卿學姐的講解的模板,看得雲裡霧裡,就感覺模板不太對勁,怎麼邊界用的是離散前的?
直至找到
發現邊界確實直接用離散後的就行,畢竟是實質是權值線段樹。
這是第一篇,講模板,poj2104,無修改的主席樹模板,求區間第k大,主席樹的典例
首先是空間,一般來說開<<5(32)倍或者直接40倍會比較好
因為初始為4倍(線段樹空間)n,每次更新最壞要logn,加起來就是n(logn+4)的空間,而2的28次方大概是2e8,一般的n都沒有這麼大(也沒有那麼大記憶體),所以32倍空間已經足夠了。
首先是前置技能:權值線段樹。
權值線段樹,顧名思義,就是以權值建樹。以往我們的線段樹存的是具體的值,而權值線段樹,存的是數量,每個結點的sum儲存該代表權值在該區間內的點的數量,安利一篇blog圖做得很棒,一看就懂。
然後就來到了我們的重點,主席樹。
再上圖
update表示我要更新的結點,更新此結點,按照普通的線段樹,自然是更新從根結點到此節點整條鏈上的點的sum值。但是主席樹就不一樣了,主席樹選擇新建一條鏈。那沒更新的點呢?繼續用以前的就行啦。所以圖中虛線鏈結的兩點其實是同乙個點,只要將父節點指向原先已經建好且沒更新的點即可。下面上的模板是我該篇最上邊引用的文章裡的,加了些注釋,且會進行說明。
#include #include #include#define max 100010
#define clr(arr,val) memset(arr,val,sizeof(arr))
using namespace std;
const int inf = 0x3f3f3f3f;
//記錄原陣列、排序後的陣列、每個元素對應的根節點
int nums[max], sorted[max], root[max];
int cnt;
struct ***
tree[max<<5];
inline int createnode( int _sum, int _l_son, int _r_son )
void insert( int & root, int pre_rt, int pos, int l, int r ) //相當於更新,每次更新一條鏈 權值線段樹
int query( int s, int e, int l, int r, int k )
int main()
sort( sorted + 1, sorted + 1 + n );
num = unique( sorted + 1, sorted + n + 1 ) - ( sorted + 1 );
for ( int i = 1; i <= n; ++i )
int l, r, k;
while ( m-- )}}
這篇模板的重點,自然是insert過程。insert其實就是update,傳入的引數pos是對應權值線段樹的值。你可以把他當做離散以後,每個葉子結點的sum值就是下標為pos(權值為pos)的點的數量,而區間1~num則代表下標1~num(權值1~num)。
在insert過程裡,我們每次要新建乙個結點,因為該結點是需要被修改的,就是我們上面所說的在傳統線段樹需要被修改的鏈上的一點。但是因為這個是主席樹,所以我們要新建而不是修改歷史版本的該結點。同時,我們新建的該結點的子結點都指向歷史版本(上乙個版本)對應的該結點的子結點(這個應該比較好理解),因為我們不確定子結點需不需要更新,或者說,不確定哪個子結點需要更新,哪個不需要。然後繼續向下遍歷,如果該子結點要更新,那麼就重複上述過程,新建一點,把歷史版本子結點的子結點(孫子結點)連到我們新建的這個子結點上。
在查詢過程,每個結點作差就代表在此查詢區間,我每個結點對應的權值區間內的點有幾個。比如我要求查詢區間第5大的,那假設我左子結點代表權值在【1,2】內的點數量,右子結點代表權值在區間【3,5】的數量。如果我左子結點的sum>=5,就代表權值在【1,2】內的點至少有5個,那麼查詢區間的第5大一定在左子結點代表的權值區間內產生;反之,自然就在右子結點代表的權值區間內產生。
感覺寫得不太好(wtcl),希望大家能看懂qaq。
最近再把動態的更了,再更幾道比較典型的題qwq(我相信我不會咕咕咕的)。
(我才不會告訴你們其實這篇blog在兩個月前就寫了一半存了草稿,一直咕到現在)
主席樹基礎介紹
自己是沒有寫主席樹教程的想法啦,畢竟網上那麼多資料,寫那些東西的人的水平比我不知道高到 去了,而且主席樹的用法不僅僅是區間第k大,好多用法我這個弱菜根本就不知道,哪有什麼寫教程的資格,不過之前隊友問過我對主席樹的理解 幫助他入門 當時自己根據自己的想法寫了點東西,就想不如把這些東西放在部落格上好了,...
主席樹 初學
現在才開始學主席樹 弱 不過不帶修改的話 還是很簡單的嘛。或者說應該叫可持久化線段樹?首先對數的區間進行離散化,這樣下面的a i 都預設為離散化以後的結果了。對於每個1.i開乙個線段樹,對於這個線段樹中的每乙個節點 l,r 表示1.i中在 l,r 中的數的個數。顯然這n個線段樹的形態大小是完全一樣的...
主席樹 模板
思想 主席樹就是一顆持久化線段樹,為什麼叫持久化了,因為它可以儲存之前的線段樹版本,並且可以拿來用,從而優化空間.至於為什麼叫主席樹了,大概是因為發明這個演算法的人的名字的緣故吧 詳細說說 主席樹是一種離線資料結構,是由很多棵線段樹組成的。第i棵線段樹存的是前i個數的資訊 每乙個線段存數字的出現次數...