要想學主席樹,首先要搞懂可持久化線段樹,因為主席樹運用到了它的思想。
主席樹的模板題是:靜態查詢區間第k小
那麼主席樹的做法就是,先把全部數字離散化,然後以每乙個字首建一棵權值線段樹,顯然,如果直接建,那麼空間上是不允許的,但是我們發現,每兩個相鄰的字首中,只有乙個數的差別,所以,他們公共部分是很多的,於是,我們就可以用到可持久化線段樹了!
首先,要明確一下,主席樹上每個節點的值的定義(我們設這個節點的管理範圍為l~r,並且現在已經將這個數列離散化了):表示在當前字首中,有多少個數的值在l~r中。
確定主席樹的定義十分重要!網上有很多講的不清楚的,搞得我懵逼了很久……
比如有下面這個數列,離散化後就是,那麼我們要以每乙個字首建一棵線段樹,首先,先建一棵空的線段樹,表示當前什麼數都沒有,然後,我們把數列裡的數乙個乙個加進去就好了,就像這樣(紅色數字表示每個節點的值,意義如上所述):
那麼首先加入第乙個數——3,這棵樹就會變成(節點裡面是這個節點的管理範圍,方便理解):
好的,主席樹就這樣造出來了!那接下來就是查詢,為了更好理解,我們先從簡單的開始,假如要查詢1~3範圍中的第k小的數,假設k=2,那麼可以直接從1~3這個字首的根開始找, 也就是綠色的那個根,那麼怎麼找呢,因為可以保證,左邊的數都比右邊的數要小,所以我們發現,現在要找的是第2小,但是左兒子的值只有1,說明在1~3這個字首裡,在1~2範圍內的只有1個數,那麼第2小一定在右兒子裡,於是我們往右兒子那裡走一步,但是如果往右兒子那裡走,k就要減去左兒子的值(蒟蒻語文不好。。實在想不到要怎麼解釋,自已意會一下吧,不難理解。。),然後因為k減了1,所以我們現在要找的就是第1小,然後發現當前節點的左兒子的值為1,k<=1,所以第k小一定在左兒子裡,於是就走過去,然後發現這是個葉子節點,他管理的範圍是3~3,說明這個第2小的數離散化之後的數是3,那麼我們輸出這個數原來是多少就好了,也就是9。
好的我們解決了在某個字首中如何查詢第k小,那麼,現在要解決的問題是,查詢區間第k小。
可能有人就會想到,你用字首和來維護這個東西,那麼要求乙個區間就可以直接用字首和相減嘛!
沒錯!就是相減。比如現在要求區間l~r的第k小,那麼我們可以用a來存1~r這個字首和上的根,b存1~l-1,那麼每一次向下查詢左右兒子的值的時候就先需要用a的左右兒子的值減去b的左右兒子的值,這樣就可以去掉1~l-1中的數,只留下l~r區間的數,然後向上面一樣查詢即可。
**如下(附有良心的注釋):
#include #include #include #include using namespace std;
int n,m,len=0,cnt=0;
int a[200010];
struct nod;
nod b[200010];
struct node;
node tree[5000010];
int gen[200010];
bool cmp(nod x,nod y){return x.x待修主席樹
詳解MySQL從入門到放棄 安裝
學習內容 1.軟體安裝及伺服器設定。2.選做,但是強烈建議 使用圖形介面軟體 n icat for sql 3.資料庫基礎知識 4.mysql資料庫管理系統 軟體安裝 mysql 鏈結 mysql nbswww.cppcns.comp 第乙個,之後解壓縮。我的目錄在c users public my...
Linux從入門到放棄 find命令詳解
功能 搜尋檔案資訊 語法find 路徑 查詢範圍 查詢資料條件 引數 find根據名稱搜尋 find name 檔名稱 全盤搜尋根據名稱忽略大小寫搜尋查詢資料層級最深深度 find 目錄 maxdepth 層數 name 檔名稱查詢資料層級最淺深度 find 目錄 mindepth 層數 name ...
Linux從入門到放棄 定時服務詳解
概念 週期性,讓系統完成相應的操作說明 1 週期性,進行資料備份操作 2 週期性,重啟服務程式 3 週期性,切割日誌 4 週期性,執行指令碼檔案實現方式 1 crond服務實現定時任務 命令crontab 檔案 var log cron 2 atd軟體實現定時任務 3 anacron軟體實現定時任務...