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

2022-06-01 18:30:14 字數 3110 閱讀 1338

目錄#2.0 部分**實現

#3.0 例題 p1168 中位數

更新日誌及說明

若並未學會,建議進入以下相應博文先行學習前置知識

[資料結構入門]線段樹

發表於 2019-11-28 20:39 dfkuaid

摘要: 線段樹的基本(建樹、區間查詢、單點修改)及高階操作(區間修改 單點查詢、區間修改 區間查詢(標記下傳、標記永久化)) 

閱讀全文   

>>   

[資料結構入門]線段樹plus - 區間乘法 & 動態開點

發表於 2021-02-05 21:52 dfkuaid

摘要: 線段樹區間乘法,動態開點及權值線段樹簡單介紹 

閱讀全文   

>>   

演算法初探 - 離散化

發表於 2020-09-25 16:01 zythonc

閱讀全文   

>>   

舉個例子,有乙個數列 \(\,(i \leq 10000,a < 10^9)\),

一般的線段樹,結點代表的區間是 \(i\) 的範圍,葉結點維護的是 \(a_\) 的值,權值線段樹代表的區間則是 \(a_i\) 的範圍,葉結點上維護 \(a_i\) 這個數出現的次數(運用了「桶」的思想),做統計用

但是 \(a_i\) 可以很大,\(i\) 卻不會很大,所以一般先對資料進行離散化,同時使用動態開點節約空間,再進行統計。

回到定義上,線段樹維護的是某乙個數出現的次數,那麼,它的結構是這樣的:

那麼,舉個例子,我們有下面這個數列:

\[\begin

a=\\end

\]將他維護成權值線段樹便是這樣的:

那麼,問題來了,我們為什麼要維護這樣乙個區間線段樹?

是為了動態地維護區間的某乙個數出現的次數,比如求動態第 \(k\) 小值。

首先,因為權值線段樹維護的是值域,而有些值域可能特別大,但數的數量可能不多,我們維護乙個數出現的次數,顯然只需要這個數相應的大小位置即可,不需要具體數值,那麼就需要離散化

scanf("%d",&n); //輸入資料

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

/*下面是離散化的過程*/

sort(a + 1,a + n + 1); //排序

int size = unique(a + 1,a + n + 1) - a - 1; //去重

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

當做單點修改,輔以動態開點

inline int create()

inline void change(int k,int l,int r,int x)

else

}

這裡只講一種利用權值線段樹維護的最常見的資料:第 \(k\) 小(大)的數對於乙個結點,我們要找它所代表的範圍內第 \(k\) 小的數,一定有以下兩種情況

簡單思考:為什麼在右子樹里找第 \(k-sum[lson]\) 小的數?而不是第 \(k\) 小的數?

這個問題留給各位自己思考,可以用畫圖的方式幫助理解

查詢**實現:

inline int query(int k,int l,int r,int kth)

int mid = (l + r) >> 1;

if (p[p[k].ls].sum >= kth)

return query(p[k].ls,l,mid,kth);

else

return query(p[k].rs,mid + 1,r,kth - p[p[k].ls].sum);

}

不難想到,相當於每次在前 \(2\times i+1\) 個數里找到第 \(k+1\) 大的數,符合權值線段樹的維護,碼就完了

#include #include #include #include #include #define inf 0x3fffffff

#define n 100010

#define ll long long

#define mset(l,x) memset(l,x,sizeof(l));

#define mp(a,b) make_pair(a,b)

using namespace std;

struct node;

node p[n << 2];

int n,cnt,tot;

ll a[n],lsh[n],b[n],tmp[n];

inline int create()

inline void change(int k,int l,int r,int x)

else

}inline int query(int k,int l,int r,int kth)

int mid = (l + r) >> 1;

if (p[p[k].ls].sum >= kth)

return query(p[k].ls,l,mid,kth);

else

return query(p[k].rs,mid + 1,r,kth - p[p[k].ls].sum);

}int main()

sort(a + 1,a + n + 1); //離散化

int size = unique(a + 1,a + n + 1) - a - 1;

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

cnt = 1;

tot = 0;

int root = create(); //建立根節點

cnt = 0;

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

}return 0;

}

歡迎到以下位址支援作者!

github:戳這裡

bilibili:戳這裡

luogu:戳這裡

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

資料結構專題 權值線段樹 學習權值線段樹,首先要了解線段樹是什麼。如果不會的可以先學習一下。權值線段樹,顧名思義是一棵線段樹。但它和普通線段樹不同 線段樹,每個節點用來維護一段區間的最大值或總和等。權值線段樹,相當於乙個桶,每個節點用來表示乙個區間的數出現的次數。我們可以用它來維護一段區間的數出現的...

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

先介紹一下離散化 桶排大家應該知道,就是開乙個陣列 下標為數值,記錄了該數值的出現次數 然後遍歷過去如果出現次數不為零,那就輸出這些數字,理論時間複雜度可以達到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...