( 資料結構專題 ) 權值線段樹

2021-10-01 04:14:26 字數 2283 閱讀 3578

( 資料結構專題 )【 權值線段樹 】

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

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

但它和普通線段樹不同:

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

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

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

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

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

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

void update( int node, int left, int right, int x ) // 樹中x出現的次數+1

if ( x<=mid ) update(lson,x);

if ( x>mid ) update(rson,x);

tree[node] = tree[node*2]+tree[node*2+1];

}

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

以下**要查詢的區間是[l,r]。

int query( int node, int left, int right, int l, int r ) // 在區間[l,r]有幾個數出現

int sum = 0;

if ( l<=mid ) sum+=query(lson,l,r);

if ( r>mid ) sum+=query(rson,l,r);

return sum;

}

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

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

為什麼要減去?

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

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

int kth( int node, int left, int right, int k ) // 返回整個區間第k大的值

題意:

給出乙個序列,一對逆序數就是滿足ia[j]條件的一對數字。每次將a陣列的最後乙個數放到陣列的第一位上,原陣列向後移動一位,得到乙個新的序列,求這些序列中最小的逆序數。(每個數都在0-n-1範圍內)

思路:逆序數的性質:乙個序列第i次迴圈的逆序數pi=p(i-1)+(n-1-a[i])-a[i] ( 自己畫一組樣例也好理解 )。用權值線段樹來找出初始狀態的逆序對,然後根據性質來更新最小值。

**:

#include // 權值線段樹

#define mid ((left+right)/2)

#define lson node*2,left,mid

#define rson node*2+1,mid+1,right

using namespace std;

const int maxn = 1e5+10;

int tree[maxn*4];

int a[maxn];

void built_tree()

void update( int node, int left, int right, int x ) // 樹中x出現的次數+1

if ( x<=mid ) update(lson,x);

if ( x>mid ) update(rson,x);

tree[node] = tree[node*2]+tree[node*2+1];

}int query( int node, int left, int right, int l, int r ) // 在區間[l,r]有幾個數出現

int sum = 0;

if ( l<=mid ) sum+=query(lson,l,r);

if ( r>mid ) sum+=query(rson,l,r);

return sum;

}int kth( int node, int left, int right, int k ) // 返回整個區間第k大的值

int main()

cout << ans << endl;

}return 0;

}

資料結構入門 線段樹plus 權值線段樹

目錄 2.0 部分 實現 3.0 例題 p1168 中位數 更新日誌及說明 若並未學會,建議進入以下相應博文先行學習前置知識 資料結構入門 線段樹 發表於 2019 11 28 20 39 dfkuaid 摘要 線段樹的基本 建樹 區間查詢 單點修改 及高階操作 區間修改 單點查詢 區間修改 區間查...

資料結構 離散化 權值線段樹

先介紹一下離散化 桶排大家應該知道,就是開乙個陣列 下標為數值,記錄了該數值的出現次數 然後遍歷過去如果出現次數不為零,那就輸出這些數字,理論時間複雜度可以達到o n 但是由於記憶體限制,不能開很大的陣列。然而 如果某個數列中的數字不要求大小確定,只要求這些數字有相對的大小就夠了的話,離散化就有了用...

資料結構 可持久化權值線段樹

解決靜態區間第k小的問題。include using namespace std const int maxn 2e5 5 int tot,n,m int sum maxn 5 rt maxn ls maxn 5 rs maxn 5 int a maxn ind maxn len inline in...