樹狀陣列(bin
aryi
ndex
edtr
ee
sbinary indexed trees
binary
inde
xedt
rees
)是一種由於維護序列字首和的資料結構。對於給定序列a
aa,我們建立乙個陣列c
cc,其中c[x
]c[x]
c[x]
儲存序列a
aa的區間[x−
lowb
it(x
)+1,
x]
[x - lowbit(x)+1, x]
[x−low
bit(
x)+1
,x]中所有數的和,即∑i=
x−lo
wbit
(x)+
1xa[
i]
\sum^_
∑i=x−l
owbi
t(x)
+1x
a[i]
。事實上, 陣列c
cc可以看做成乙個樹形結構,該結構滿足以下性質:
每個內部節點c[x
]c[x]
c[x]
儲存以它為根的子樹中所有葉節點的和。
每個內部節點c[x
]c[x]
c[x]
的子節點個數等於low
bit(
x)
lowbit(x)
lowbit
(x)的個數(low
bit(
x)=x
&(−x
)lowbit(x) = x \& (-x)
lowbit
(x)=
x&(−
x))。除了樹根外,每個內部節點c[x
]c[x]
c[x]
的父節點是c[x
+low
bit(
x)
]c[x+lowbit(x)]
c[x+lo
wbit
(x)]
。樹的深度為o(l
ogn)
o(logn)
o(logn
)。樹狀陣列查詢字首和
int
ask(
int x)
樹狀陣列單點增加同時維護字首和void
add(
int x,
int y)
在執行所有操作之前, 我們需要對樹狀陣列進行初始化——針對原始序列a
aa構造乙個樹狀陣列。
方法是:從小到大一次考慮每個節點x
xx,借助low
bi
tlowbit
lowbit
運算掃瞄它的子節點並求和。時間複雜度為o(n
)o(n)
o(n)
。線段樹(seg
ment
segment
segmenttr
ee
tree
tree
)是一種基於分治思想的二叉樹, 用於在區間上進行資訊統計, 可儲存複雜資訊, 比樹狀陣列更通用, 但是**量較大。
1.線段樹的每個節點都代表著乙個空間。
2.線段樹具有唯一的根節點, 代表的區間是整個統計範圍, 如[1, n]。
3.線段樹的每個葉子節點都代表乙個長度為1的區間[1, x]。
4.對於每個內部節點[l, r],它的左子節點是[l, mid], 右子節點是[mid+1,r],其中mid = (l + r) / 2(向下取整)。
線段樹的向上更新
以求區間最大值為例:
void
pushup
(int p)
以求區間和為例:
void
pushup
(int p)
在精準更新某個特定區間後, 所有以這個區間為子區間的區間都要依次更新。
線段樹的單元
struct node
線段樹的建立
相當於對陣列維護的初始化
void
build
(int p,
int l,
int r)
int mid =
(l + r)
>>1;
build
(p<<
1, l, mid)
;build
(p<<1|
1, mid +
1, r)
;//對對應某區間的節點的兩個子節點更新
pushup
(p);
}
線段樹的區間查詢
較靈活,可以根據題意進行靈活地改動
這裡以求某段區間中的最大值為例(於是用這個模板也可以求出最小值和極差)
int
ask(
int p,
int l,
int r)
線段樹的單點修改void
change
(int p,
int x,
int v)
int mid =
(t[p]
.l + t[p]
.r)/2;
if(x <= mid)
change
(p<<
1, x, v)
;else
change
(p<<1|
1, x, v)
; t[p]
.val =
max(t[p<<1]
.val, t[p<<1|
1].val)
;}
線段樹的區間修改
為了節省時間, 通常在結構體裡多維護乙個變數lazy標記,這樣可以減少更新子節點的次數。注意有的題目要求要對每個葉子節點更新,就不可以用lazy標記。有的題目裡可能本身的資訊就可以充當lazy標記起到作用,就可以不用多維護變數。
void
pushdown
(int p)
t[p<<1]
.lazy +
= t[p]
.lazy;
t[p<<1|
1].lazy +
= t[p]
.lazy;
t[p<<1]
.lazy =0;
}void
change
(int p,
int l,
int r,
int d)
pushdown
(p);
int mid =
(t[p]
.l + t[p]
.r)>>1;
if(l <= mid)
change
(p<<
1, l, r, d);if
(r > mid)
change
(p<<1|
1, l, r, d)
;pushup
(p);
}int
ask(
int p,
int l,
int r)
樹狀陣列與線段樹
推一下關於樹狀陣列的講解部落格 和線段樹的講解 package test2 public class 線段樹 int len a.length segtree t buildtree 0,len 1,a int sum0 2 query t,0,2 int sum1 3 query t,1,3 查詢...
樹狀陣列與線段樹(三)
找規律題 1.螺旋折線 如下圖所示的螺旋折線經過平面上所有整點恰好一次。對於整點 x,y 我們定義它到原點的距離 dis x,y 是從原點到 x,y 的螺旋折線段的長度。例如 dis 0,1 3,dis 2,1 9 給出整點座標 x,y 你能計算出 dis x,y 嗎?輸入格式 包含兩個整數 x,y...
樹狀陣列與線段樹(二)
樹狀陣列 1.小朋友排隊 n n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。每個小朋友都有乙個不高興的程度。開始的時候,所有小朋友的不高興程度都是 0 0 如果某個小朋友第一次被要求交換,則他的不高興程度增加 1 1 如果第二次要求他交換,則他的不...