主席樹基礎

2021-09-11 04:24:13 字數 2187 閱讀 9781

主席樹明明是個很棒的東西,可惜網上卻很難找到很好的模板/講解

包括卿學姐的講解的模板,看得雲裡霧裡,就感覺模板不太對勁,怎麼邊界用的是離散前的?

直至找到

發現邊界確實直接用離散後的就行,畢竟是實質是權值線段樹。

這是第一篇,講模板,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個數的資訊 每乙個線段存數字的出現次數...