權值線段樹學習筆記 Part 1
阿新 • • 發佈:2022-04-04
權值線段樹
就是以下標為值域的一棵線段樹。
定義
引用一下這篇日報中的例子:
假設用權值線段樹維護一個數組: \(\left\{ 1,1,2,2,2,3,4,5,6,7,8 \right\}\)
初始權值線段樹時所有節點為 0
插入陣列中的 1 後
插入陣列中的 2 後
全部插入後
時間複雜度
因為權值線段樹也是一棵線段樹,所以每次操作的複雜度還是 \(\log\) 級別的,也就是 \(\log l\)(\(l\) 表示其中的最大權值,因為線段樹是開在值域上的)。
如果沒有動態開點的話,空間複雜度就是正常的 \(O(4 \times l)\),因此一般情況下權值線段樹要進行離散化。
操作
插入一個數
void update(int num,int p=1,int l=1,int r=n){
if(num>r||num<l) return;
//按這個數的大小左右二分,最多Logn次就到葉節點,所以每次修改的時間複雜度為O(logn)
sgt[now]++;//可以直接修改
if(l==r) return;
Updata(num,L);Updata(num,R);
}
查詢第 \(k\) 大的數
int query(int num,int p=1,int l=1,int r=n){ if(l==r)//到葉節點說明找到了 return left; if(s[lc].v>=num) return query(num,L);//如果在左子樹就往左子樹找 return query(num-s[lc].v,R);//不在就往右子樹找 }