主席樹(模板)

2022-03-16 14:34:43 字數 1463 閱讀 8840

求區間第k大的值;

我們需要在短時間內回答數目巨大的問題,這個演算法的核心是空間換時間;

每個點建乙個線段樹,是的;

我們先離散化所有權值,使得當前的權值在1到n範圍內,恰巧是vector裡的下標;

對於每乙個點,我們分成左二子和右兒子,分別存放當前區間的左半部分和右半部分,維護左右節點的數量;

我們怎麼求區間第k大呢?

運用字首和的思想,我們其實建出來的很多樹左右數量是遞增的;

遍歷每乙個節點,現將當前節點繼承前一節點的歷史狀態,再將節點數+1,根據當前節點的大小判斷插在左邊還是右邊,遞迴進行此操作;

對於區間【l,r】,我們將l-1的樹拿出來,r的樹拿出來,每個樹的節點數就是1到 i 的節點數,先兩個左子樹的節點數相減,得到的數與當前k比較,

如果大於k就在左子樹里找,如果小於k就在右子樹里找k-sum_l個;也是遞迴實現;

實質就是每次加點,查詢時套用字首和,根據數量判斷向下遞迴的方向,從而減少時間複雜度;

時刻注意每個點代表的歷史狀態,誰和誰對應;

離散化操作

sort(v.begin(),v.end());

v.erase(unique(v.begin(),v.end()),v.end());

先將陣列排序,然後unique(),此時函式操作是將重複的數字都扔到後面,返回不重複序列的最後乙個數的下乙個數的下標;這時我們將後面刪去即可;

取得離散後的數lower_bound即可;

根據學長的傳承,空間開40倍;

section (區間)

#include#include

#include

#include

using

namespace

std;

const

int maxn=2e5+10

;vector

v;introot_sec[maxn];

struct

node

t[maxn*40

];int get_id(int

x)int

n,m,a[maxn],cnt;

void update(int l,int r,int x,int &y,int

pos)

int query_id(int l,int r,int x,int y,int

sum_k)

intmain()

sort(v.begin(),v.end());

v.erase(unique(v.begin(),v.end()),v.end());

for(int i=1;i<=n;i++) update(1,n,root_sec[i-1

],root_sec[i],get_id(a[i]));

for(int i=1;i<=m;i++)

return0;

}

至於為什麼叫主席樹,是因為發明他的人叫hjt;

主席樹 模板

思想 主席樹就是一顆持久化線段樹,為什麼叫持久化了,因為它可以儲存之前的線段樹版本,並且可以拿來用,從而優化空間.至於為什麼叫主席樹了,大概是因為發明這個演算法的人的名字的緣故吧 詳細說說 主席樹是一種離線資料結構,是由很多棵線段樹組成的。第i棵線段樹存的是前i個數的資訊 每乙個線段存數字的出現次數...

主席樹模板

維護n棵1 i的字首權值線段樹,每次查詢減一下就好了。poj 2104就是模板題,裸的靜態第k大,需要先離散化,不會的就用lower bound 多試試,研究研究應該就能懂。include include include include using namespace std const int m...

模板 主席樹

譴責奶人的hsz巨神 靜態版本 求區間第k大 可持久化也沒那麼高大上嘛,主席樹本質上就是多棵線段樹,求第k大就類似平衡樹的第k大。stay foolish,stay hungry,stay young,stay include include include include using namesp...