pta題目鏈結
**學長
單純的模板題目,求區間第k大
離散化的目的是防止資料過大,建樹過程中造成記憶體過大。大致過程就是講整組資料排序,然後按照順序賦予乙個序號,使得序號和資料對應,建樹插入的就是對應序號。去重就是刪除重複的部分採用乙個函式unique將重複的部分放到最後,並返回重複部分的第乙個位址,要求資料有序
for
(int i =
1; i <= n; i++
)sort
(v.begin()
, v.
end())
; v.
erase
(unique
(v.begin()
, v.
end())
, v.
end())
;
然後這是乙個查詢資料對應序號的函式
inline
intgetid
(int x)
lower_bound返回大於等於val的第乙個元素位置
主席樹是可持久化線段樹的一種,用於查詢歷史某個狀態,然後怎麼快速查詢某個歷史版本,採用空間換時間的思路,第一反應就是每個版本都存乙份出來,但是這樣需求空間太大,怎麼優化空間。
觀察每次資料的更新或者修改,我們發現變化的只有這次修改的葉子結點一直向上到根結點這一條鏈,其他都和上乙個版本一樣,那麼這些相同部分就是可以空間優化的部分,我們每次都更新一條新的鏈(連線有資料修改的部分),那些重複的部分我們則直接鏈結到這條新的鏈上,舉個例子t[x]是乙個結點,他的左邊被我更新了,我遞迴修改t[x].l(線段樹的修改套路),t[x].r=t[y].r,直接等於上一次這個位置結點的右邊部分,假設y是上一同乙個位置的結點的序號。
inline
void
update
(int l,
int r,
int& x,
int y,
int pos)
//y是同位置的上乙個版本序號
區間查詢類似權值線段樹的樣式,本題求第k大,然後我是從小到大排序,就是求排完序後從左數第k個,第a個到第b個之間就是第a-1個版本和第b個版本之間的差距,先算兩個版本右子樹的sum差,為什麼都是右邊的:因為通過分治的思路,一直判斷第k的在當前結點的左邊還是右邊,然後左邊是大於本身的,知道的是第k大,就需要看大的部分,所以是r。如果差大於k就證明第k大包含在右邊,查右邊。但是在查左邊的過程中,已經去掉了 差 個大的,傳遞的k變成k-sum
inline
intquery
(int l,
int r,
int x,
int y,
int k)
x在主函式裡的輸入是root[a-1],y是root[b],root是版本
**
#include
using
namespace std;
const
int maxn =
2e5+10;
struct qwq
t[maxn*40]
;int root[maxn]
, arr[maxn]
, n, m, cnt =0;
vector<
int>v;
inline
intgetid
(int x)
inline
void
update
(int l,
int r,
int& x,
int y,
int pos)
inline
intquery
(int l,
int r,
int x,
int y,
int k)
intmain()
sort
(v.begin()
, v.
end())
; v.
erase
(unique
(v.begin()
, v.
end())
, v.
end())
;for
(int i =
1; i <= n; i++
)for
(int i =
0; i < m; i++
)return0;
}
主席樹模板以及個人理解
主席樹的原理其他部落格已經寫的很詳細了,我就不加贅述了。主要是記錄一下個人的部分理解以及模板,以便以後 主席樹是一種可持久化資料結構,或者說,可持久化線段樹,利用主席樹 可以檢視線段樹的歷史狀態並對其修改 具體做法就是每個點開一顆線段樹 為了節省空間採取動態開點 建樹的時間複雜度是 o nlogn ...
主席樹 初學
現在才開始學主席樹 弱 不過不帶修改的話 還是很簡單的嘛。或者說應該叫可持久化線段樹?首先對數的區間進行離散化,這樣下面的a i 都預設為離散化以後的結果了。對於每個1.i開乙個線段樹,對於這個線段樹中的每乙個節點 l,r 表示1.i中在 l,r 中的數的個數。顯然這n個線段樹的形態大小是完全一樣的...
主席樹 模板
思想 主席樹就是一顆持久化線段樹,為什麼叫持久化了,因為它可以儲存之前的線段樹版本,並且可以拿來用,從而優化空間.至於為什麼叫主席樹了,大概是因為發明這個演算法的人的名字的緣故吧 詳細說說 主席樹是一種離線資料結構,是由很多棵線段樹組成的。第i棵線段樹存的是前i個數的資訊 每乙個線段存數字的出現次數...