1. 程式人生 > 其它 >權值線段樹學習筆記 Part 1

權值線段樹學習筆記 Part 1

權值線段樹

就是以下標為值域的一棵線段樹。

定義

引用一下這篇日報中的例子:
假設用權值線段樹維護一個數組: \(\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);//不在就往右子樹找
}