可持久化線段樹模板 解釋(洛谷 P3834)

2021-09-26 10:38:08 字數 3078 閱讀 4833

模板鏈結

可持久化線段樹是一種可持久化結構,需要知道的前導知識有:線段樹、權值線段樹、離散化、線段樹的動態開點。說實話,當蒻苟我做了那麼多**的線段樹後發現,可持久化線段樹(僅限模板)還是很好寫的。

什麼叫可持久化?

可以想象,有乙個線段樹,他除了可以進行普通的查詢修改操作,還可以記錄歷史版本,即,我們可以調取任意修改次數時的狀態。我們這時可以想象乙個樸素的方法完成這個操作:

對於每次修改,我們都將我們建好的這棵樹整體複製乙個副本,然後我們在這個副本上修改。

我們知道線段樹的空間複雜度為o (n)所以對於m次查詢,就是 o(nm),從空間上就**了。時間更不要說了。

這是就靠我們的動態開點技術了。

如果我們想修改3號節點。我們易知,pushup操作遍及下圖中的綠色節點,其他節點不涉及。

依次特性,我們每次創立新節點時候,知創立更改的節點,鏈結到原樹上:

這樣的化,空間複雜度降為o(nlogn)時間複雜度o(logn)。

概念理解完,看題。這個題的意思是讓我們查詢區間中的第k小的值。按照發明人的意思:對於乙個序列,我們每次建立乙個字首的權值線段樹。即,我們建立維護[1, r],(1<= r <= n)區間的權值線段樹,則我們定每乙個權值線段樹為本可持久化線段樹中的乙個歷史版本。我們通過字首和思想。我們想想要查詢[l,r]中值為k的數量。則,肯定為[1, r]中k的數量減去[1, l-1]的k的數量。於是,我們每次查詢r版本l-1版本的權值線段樹的k的數量,然後結合權值線段樹基本查詢方式。可以解出答案。

詳細實現過程請看**注釋。

下面是模板**:

#include

#include

#include

#include

#include

#include

#include

#include

#define ll long long

using

namespace std;

const

int n =

2e5+5;

int root[n]

, cnt;

int lisan[n]

;int su[n]

;int mx;

// 先看main函式。

struct node

tr[n<<5]

;inline

intgetn

(int g)

void

change

(int l,

int r,

int&p,

int pre,

int v)

intask

(int l,

int r,

int l,

int r,

int k)

intmain()

sort

(lisan+

1, lisan+n+1)

; mx =

unique

(lisan+

1, lisan+n+1)

- lisan;

//離散化過程

for(

int i =

1; i <= n; i++

)change(1

, mx-

1, root[i]

, root[i-1]

,getn

(su[i]))

;//root[i]是指第i個歷史版本的權值線段樹的歷史版本根節點編號

//從1到mx-1的值域,以root[i-1]權值線段樹為原型,插入su[i],建立root[i]的權值線段樹。

while

(m--

)return0;

}//確實比那些**線段樹好寫吧 2333333

ps.change ask函式的l,r形參是值域範圍,不是該節點的左右孩子,更不是區間的範圍!另一道題。super mario hdu - 4417

#include

#include

#include

#include

#include

#include

#include

#include

#define ll long long

using

namespace std;

const

int n =

1e5+5;

struct node

tr[n<<5]

;int su[n]

;int lisan[n]

;int root[n]

;int mx, _cnt, cnt, n, m;

inline

intgetn

(int x)

void

change

(int l,

int r,

int pre,

int&p,

int v)

intask

(int l,

int r,

int r,

int l,

int k)

void

print

(int p,

int l,

int r)

intmain()

printf

("%d\n"

,ask(1

, mx-

1, root[r+1]

, root[l]

, gg));}}}

洛谷P3834 可持久化線段樹 主席樹 模板

題目 無法忍受了,我要寫主席樹!解決區間第 k 大查詢問題,可以用主席樹,像字首和一樣建立 n 棵字首區間的權值線段樹 然後 n 棵線段樹可以共用一些節點 線段樹的 sum 可以相減,利用這個查詢即可 什麼嘛,主席樹也沒我想得那麼難 蠻簡單的 如下 include include include i...

洛谷P3919可持久化線段樹

有了可持久化陣列,便可以實現很多衍生的可持久化功能 例如 可持久化並查集 如題,你需要維護這樣的乙個長度為 n 的陣列,支援如下幾種操作 在某個歷史版本上修改某乙個位置上的值 訪問某個歷史版本上的某一位置的值 此外,每進行一次操作 對於操作2,即為生成乙個完全一樣的版本,不作任何改動 就會生成乙個新...

洛谷3834 可持久化線段樹(主席樹模板)

主席樹經典問題,靜態查詢區間第k大數。拖了很久都沒有寫的模板。結果差不多此次 你賽都考,痛定思痛後,決定好好研究下。主席樹可以近似理解為權值線段樹的字首和的形式,詳細講解可參考wcr寫的主席樹講解 傳送門。回到該題,因為不涉及修改操作,所以我們建立n棵權值線段樹,先將資料離散化,這樣主席樹的權值就在...