權值線緞樹

2021-10-04 23:10:22 字數 4149 閱讀 8127

權值線緞樹就是特殊的線緞樹,他的結構和普通線緞樹一樣,每個結點都是表示一段區間的範圍(因此也需要開四倍空間),但是其每個結點儲存的是該區間的數出現的次數。

權值線段樹維護的是桶(形象理解)

1、快速計算一段區間的數的出現次數。

2、快速找到第k大或第k小值。

1、注意題目中資料範圍一般較大,數的值一般高達1e9左右,如果就這麼插入權值線緞樹會爆記憶體(高達4e9,哪頂的住),這就需要用到離散化了因此一般是先對序列離散化,再將其插入權值線緞樹。

//離散化

vector

a(n)

;for

(auto& it:a)cin>>it;

sort

(a.begin()

,a.end()

);a.

erase

(unique

(a.begin()

,a.end()

),a.

end(

));

再定義乙個函式用以獲取數在離散化後的序列中的id值。

int gid

(ll x)

2、離散化之後就是往樹內插入數了

const int maxn

=2e5+5

;ll t[

maxn

<<2]

;//用t陣列來存樹的結點值,記得開四倍空間

void

update

(int l,int r,int rt,int id)

int mid=l+

((r-l)

>>1)

;//這個括號一定要加,坑了很多次了,位運算優先順序低

if(id<=mid)

update

(l,mid,rt<<

1,id)

;else

update

(mid+

1,r,rt<<1|

1,id)

; t[rt]

= t[rt<<1]

+t[rt<<1|

1];return

;}

3、既然是線緞樹,他也有查詢操作

①查詢某個數出現的次數

//求某個數的個數

int query

(int l,int r,int rt,int id)

②查詢某個區間內所有數出現的總次數

(這個也包括了求單個數,只要l=r=id即可)

//求某個區間數的個數

int query

(int l,int r,int rt,int l

,int r

)

4、查詢第k大的數

//求第k大的數

int kth

(int l,int r,int rt,int k)

同理查詢第k小的數也就知道怎麼做了。

這裡附上整個板子,查詢第k小的數和4大同小異,就不給出了。

#include 

#include

#include

#include

#include

#include

#include

#include

#include <

set>

#include

#include

#include

#include

using namespace std;

#define ms

(a, x)

memset

(a, x,

sizeof

(a))

#define fore

(i, a, n)

for(long long i = a; i < n; i++

)#define ford

(i, a, n)

for(long long i = n -

1; i >= a; i--

)#define si

(a)scanf

("%d"

,&a)

#define sl

(a)scanf

("%lld"

,&a)

#define sii

(a, b)

scanf

("%d%d"

,&a,

&b)#define siii

(a, b, c)

scanf

("%d%d%d"

,&a,

&b,&c)

#define sll

(a, b)

scanf

("%lld%lld"

,&a,

&b)#define slll

(a, b, c)

scanf

("%lld%lld%lld"

,&a,

&b,&c)

#define debug

(a) cout << a << endl

#define pr

(a)printf

("%d "

,a)#define endl '\n'

#define pi acos(-

1.0)

#define tr t[root]

#define lson t[root <<1]

#define rson t[root <<1|

1]#define io ios:

:sync_with_stdio

(false

), cin.

tie(0)

#define ull unsigned long long

#define ll long long

const double eps =

1e-8

;inline int sgn

(const double &x)

const int inf=

0x3f3f3f3f

;const int maxn

=2e5+5

;ll sum[

maxn

<<2]

;vectora;

ll t[

maxn

<<2]

;int gid

(ll x)

void

update

(int l,int r,int rt,int id)

int mid=l+

((r-l)

>>1)

;if(id<=mid)

update

(l,mid,rt<<

1,id)

;else

update

(mid+

1,r,rt<<1|

1,id)

; t[rt]

= t[rt<<1]

+t[rt<<1|

1];return;}

//求某個數的個數

int query

(int l,int r,int rt,int id)

//求某個區間數的個數

int query

(int l,int r,int rt,int l

,int r

)//求第k大的數

int kth

(int l,int r,int rt,int k)

int main()

int x;

si(x)

; cout<<

query(1

,sz,1,

gid(x)

)

sii(l,r)

; cout<<

query(1

,sz,1,

gid(l)

,gid

(r))

si(k)

; cout<<

kth(

1,sz,

1,k)

<}

例題:hdu - 6609 find the answer

權值線段樹

維護全域性的值域資訊,每個節點記錄的是該值域的值出現的總次數。使用二分的思想 離散化的時候,需要用到 支援查詢全域性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 ...