目錄#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...