權值線緞樹就是特殊的線緞樹,他的結構和普通線緞樹一樣,每個結點都是表示一段區間的範圍(因此也需要開四倍空間),但是其每個結點儲存的是該區間的數出現的次數。
權值線段樹維護的是桶(形象理解)
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 ...