20190616 權值線段樹

2022-05-01 13:36:11 字數 1808 閱讀 3054

線段樹咕咕咕

我來寫乙個好寫的權值線段樹的解析吧

權值線段樹是什麼

線段樹每個點維護的是點的值,而權值線段樹葉子點維護的是乙個數出現的次數,父節點維護的是它代表的區間裡的數出現的次數的和

權值線段樹基本操作

其實權值線段樹的基本操作與線段樹沒有太大的不同

建樹

注意:由於乙個葉子節點代表乙個數出現的次數,所以,在數的範圍非常大時,我們常常需要把這些數排個序,按排序重新賦值(因為權值線段樹里數本身的值不重要,我們只需要關注它出現的次數),這也叫做離散化

void build(int l,int r,int

ro)}

新增

就是找到代表這個數的葉子節點,將它的權值++

void add(int x,int

ro)}

查詢出現次數

例題:luogu p1903 逆序對

查詢和線段樹的查詢操作一樣,

若節點代表的區間與要查詢的區間對應,返回它的權值

若要查詢的區間處於節點左子節點的區間內,去它的左子節點查詢

若要查詢的區間處於節點右子節點的區間內,去它的右子節點查詢

若要查詢的區間橫跨節點左右子節點的範圍,那分別去左右子節點查詢,並加和

int find(int l,int r,int

ro)}

查詢第k大的數

例題:luogu p3332 [zjoi2013]k大數查詢(這是我在洛谷裡能找到的有關係的題)

查詢第k大的數,也就相當於查詢第kk(kk = n- k + 1)小的數

若kk<節點左子節點的範圍,在左子節點裡找就好了

若kk>節點左子節點的範圍,說明這個數在右子節點裡,到右子節點找,但是,需要注意的是,kk的值要減去左子節點的範圍,代表我們要在右子樹里找第kk - tr[zuo].w + 1小的數

若查詢到葉子節點,那葉子節點代表的數即為所求

int numk(int l,int r,int ro,int

k)}

貼乙個40分逆序對**

#include#include

#include

using

namespace

std;

struct

ina[

500005

];struct

node

tr[4000005

];void build(int l,int r,int

ro)}

int find(int l,int r,int

ro)}

void add(int x,int

ro)}

bool cmp(in x,in

y)bool cmpp(in x,in

y)int

main()

sort(a + 1,a + 1 +n,cmp);

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

sort(a + 1,a + 1 +n,cmpp);

build(

1,n,1

);

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

printf("%d

",ans);

return0;

}

歡迎大佬指出錯誤啊

權值線段樹

維護全域性的值域資訊,每個節點記錄的是該值域的值出現的總次數。使用二分的思想 離散化的時候,需要用到 支援查詢全域性k小值,全域性rank,前驅,後繼等。單詞操作時間複雜度為o logn 空間複雜度為o n 相對於平衡樹的優勢 簡單,速度快 劣勢 值域較大時,我們需要離散化,變成離線資料結構 我認為...

權值線段樹

include using namespace std int n,m,tre 10003 4 laz 10003 4 void pushdown int num void update int num,int le,int ri,int x,int y,int z pushdown num int...

權值線段樹

權值線段樹是線段樹的一種,但是它與線段樹不同 線段樹的每個結點是用來維護一段區間的最大值或總和 而權值線段樹的每個結點儲存的一段區間有多少個數 權值線段樹主要用來查詢區間第k大或者第k小的值 現在有乙個陣列x 10 對陣列排序後為x 10 每個數的個數如下 1 32 2 3 24 1 5 18 1 ...