權值線段樹 基礎入門知識詳解

2022-05-29 17:51:09 字數 1206 閱讀 6346

學習權值線段樹,首先要了解線段樹是什麼。如果不會的可以先學習一下。

權值線段樹,顧名思義是一棵線段樹。

但它和普通線段樹不同:

線段樹,每個節點用來維護一段區間的最大值或總和等。

權值線段樹,相當於乙個桶,每個節點用來表示乙個區間的數出現的次數

我們可以用它來維護一段區間的數出現的次數,從它的定義上來看,它可以快速計算一段區間的數的出現次數。

此外,它還有乙個重要功能,在於它可以快速找到第\(k\)大或第\(k\)小值,下面會做詳細解釋。

其實,它就是乙個桶,桶能做到的它都可以用更快的速度去完成。

新增和普通線段樹類似,遞迴到葉子節點時給\(f[v]+1\)。

以下**要新增的數是\(x\),也就是\(x\)出現的次數\(+1\)。

void add(int l,int r,int v,int x)

查詢乙個數出現的次數

如新增操作,遞迴到葉子節點時\(f[v]\)的值即為所求次數。

以下**要查詢的數是\(x\)。

int find(int l,int r,int v,int x)

}

查詢一段區間的數出現的次數

與線段樹查詢同理,不斷遞迴二分。

以下**要查詢的區間是\([x,y]\)。

int find(int l,int r,int v,int x,int y)

}

查詢所有數的第k大值

這是權值線段樹的核心,思想如下:

到每個節點時,如果右子樹的總和大於等於\(k\),說明第\(k\)大值出現在右子樹中,則遞迴進右子樹;否則說明此時的第\(k\)大值在右子樹中,則遞迴進左子樹,注意:此時要將\(k\)的值減去右子樹的總和。

為什麼要減去?

如果我們要找的是第\(7\)大值,右子樹總和為\(4\),\(7-4=3\),說明在該節點的第\(7\)大值在左子樹中是第\(3\)大值。

最後一直遞迴到只有乙個數時,那個數就是答案。

int kth(int l,int r,int v,int k)

}

權值線段樹的基礎知識就是這些了,相信你都學會了。

希望你能夠靈活變通,在今後的oi生涯中更上一層樓。

如果你想學習高階知識,可以看看【主席樹】可持久化線段樹

權值線段樹

維護全域性的值域資訊,每個節點記錄的是該值域的值出現的總次數。使用二分的思想 離散化的時候,需要用到 支援查詢全域性k小值,全域性rank,前驅,後繼等。單詞操作時間複雜度為o logn 空間複雜度為o n 相對於平衡樹的優勢 簡單,速度快 劣勢 值域較大時,我們需要離散化,變成離線資料結構 我認為...

權值線段樹

include using namespace std int n,m,tre 10003 4 laz 10003 4 void pushdown int num void update int num,int le,int ri,int x,int y,int z pushdown num int...

權值線段樹

權值線段樹是線段樹的一種,但是它與線段樹不同 線段樹的每個結點是用來維護一段區間的最大值或總和 而權值線段樹的每個結點儲存的一段區間有多少個數 權值線段樹主要用來查詢區間第k大或者第k小的值 現在有乙個陣列x 10 對陣列排序後為x 10 每個數的個數如下 1 32 2 3 24 1 5 18 1 ...