權值線段樹就是把線段樹的每個點權,賦予一定的含義,比如數字出現的次數,數值字首出現的次數,並用區間求和維護乙個字首資訊,比如數字出現的次數,第k大等(不能實現區間第k大),字首第k大等。
權值線段樹本質是線段樹維護桶,桶是一種資料結構。資料結構的用途是以一種特殊方式統計資料,使得我們能夠快速地修改、查詢我們想要的那部分資料。但是一般我們在想要統計一組資料的時候,我們更關注的是這些資料都是什麼。就比如我們現在要統計乙個數列,我們更關心的是這個數列裡到底有那些數,而不是特別關心這些數都出現了幾次。
桶就打破了這個現狀,作為一種「特殊」的資料結構,它所統計的就是每個資料在資料集合中一共出現了多少次
在實現上,由於值域範圍通常較大,權值線段樹會採用離散化或動態開點的策略優化空間。
1、離線處理+離散化
2、因為只有單點修改,所以可以省略pushup函式
3、前驅、後繼的求法
4、按照每個數出現的次數建樹
5、還有其他解法:splay、treap、樹狀陣列+二分,等等
#define ls i<<1
#define rs i<<1|1
#define mid ((l+r)>>1)
#define lson ls,l,mid
#define rson rs,mid+1,r
const
int maxn=
1e5+7;
int n,m,sum[maxn<<2]
,a[maxn]
,b[maxn]
,c[maxn]
,cnt;
void
add(
int x,
int k,
int i=1,
int l=0,
int r=cnt-1)
intkth
(int x,
int i=1,
int l=0,
int r=cnt-1)
intquery
(int x,
int i=1,
int l=0,
int r=cnt-1)
intmain()
sort
(b,b+cnt)
; cnt=
unique
(b,b+cnt)
-b;for
(int i=
0;i(c[i]!=4
) a[i]
=lower_bound
(b,b+cnt,a[i]
)-b;
for(
int i=
0;i)}
題目大意:給定乙個(每個數的範圍在[1,n])陣列,可以將反覆將陣列第乙個數移到最後一位。求其中的最小逆序數。
1、逆序數的樹狀陣列模板(就是權值線段樹的一種)
2、把a[0]移到最後後,減少逆序數a[0],同時增加逆序數n-a[0]-1個。值變化:ans-a[0]+n-a[0]-1;
const
int maxn=
5e3+5;
int n,a[maxn]
,t[maxn]
,sum;
intlowbit
(int x)
void
add(
int i,
int x)
}int
query
(int i)
return ans;
}int
main()
sum=ans;
for(
int i=
1;i<=n;i++
)printf
("%d\n"
,sum);}
}
待更新 權值線段樹 模板
ps 維護區間和,時間複雜度 o n logn o nlogn o nlog n include using namespace std typedef long long ll define lson l,m,rt 1 define rson m 1,r,rt 1 1 define pushup ...
線段樹練習題一
線段樹練習題一 description 桌子上零散地放著若干個盒子,桌子的後方是一堵牆。如右圖所示。現在從桌子的前方射來一束平行光,把盒子的影子投射到了牆上。問影子的總寬度是多少?分析 給線段樹每個節點增加乙個域cover。cover 1表示該結點所對應的區間被完全覆蓋,cover 0表示該結點所對...
線段樹練習題二
線段樹練習題二 description 桌子上零散地放著若干個不同顏色的盒子,桌子的後方是一堵牆。如右圖所示。問從桌子前方可以看到多少個盒子?假設人站得足夠遠 輸入時,由底向上,從左到右 分析 cover 0表示該區間由多種顏色組成。cover 0表示該區間只有一種單一的顏色cover,最後用個桶統...