zkw
zkwzk
w線段樹作為迴圈式線段樹具有較小的常數.(其實樹狀陣列本質上就是線段樹…
下標為[1,
n]
[1,n]
[1,n
],預處理乙個2
k>
n2^k>n
2k>n.
然後總空間為2k+
12^
2k+1
.(2 k+
1<4n
2^<4n
2k+1
<4n
)後面令k=2
kk=2^k
k=2k
.那麼乙個葉子x
xx的位置在x+k
x+kx+
k.
for
(x +
= k; x;x /=2
)...
.
直接遍歷到根
因為z kw
zkwzk
w線段樹是自底往上求,所以一般使用標記永久化的tri
ck
trick
trick.
所以如果維護的標記比較繁雜,還是打普通線段樹比較好.
當遇到區間求和和區間修改的時候,我們令l+=
k−1,
r+=k
+1
l+=k-1,r+=k+1
l+=k−1
,r+=
k+1,即變為開區間.(這個是為了和的上傳
當只有區間求和和單點修改的時候,我們可以考慮轉化為左開右閉區間.
乙個區間加是這樣的:
void
add(
int l,
int r,ll x)
for(l +
= r;l/=2
; s[l]
+= l*x)
;}
對應的區間求和:
ll sum
(int l,
int r)
for(l+
=r;l/=2
;ans+
=ad[l]
*l);
return ans;
}
這個在沒有修改的情況下還是很好求的,只要預處理一下就好.
但是如果遇上區間標記呢?(比如區間加
z kw
zkwzk
w在pp
tppt
ppt內有講到乙個核心思想:
標記和值都是相對的數,那麼我們何必同時維護標記和值呢?
為了同化,我們直接差分,這樣取原值我們直接遍歷到根求和即可.
具體地,比方說我們要維護區間min
\min
min:
那麼我們令dmn
[i]=
mn[i
]−mn
[i/2
]dmn[i]=mn[i]-mn[i/2]
dmn[i]
=mn[
i]−m
n[i/
2],m n[
i]
mn[i]
mn[i
]表示區間最小值,**內實際上只保留dmn
dmndm
n.預處理:
for
(int i=
1;i<=n;i++
) mn[i+k]
=a[i]
;for
(int i=k-
1; i;i--
)
對應的區間加應該是這樣的:
void
upd(
int x)
void
add(
int l,
int r,ll x)
for(
;l/=2;
upd(l));
}
求min
\min
min:
int
min(
int l,
int r)
int ans=
min(l+mn[l]
,r+mn[r]);
for(
;l /=2
;) ans +
= mn[l]
;return ans;
}
線段樹和zkw線段樹
好啦,我們就開始說說線段樹吧 線段樹是個支援區間操作和查詢的東東,平時的話還是蠻實用的 下面以最基本的區間加以及查詢區間和為例 線段樹顧名思義就是棵樹嘛,葉子節點是每個基本點,它們所對應的父親就是它們的和,具體如下圖 但是對於這樣的線段樹來說,操作所需的時間是遠達不到我們的要求的 會被t 因為我們會...
鏈結 zkw線段樹
資料結構 走近zkw線段樹 一 資料結構 走近zkw線段樹 二 線段樹的擴充套件之 zkw線段樹 include define lc x x 1 define rc x x 1 1 using namespace std const int maxn 100005 int max int a,int...
ZKW線段樹之旅 1
膜拜zkw神犇。orz。zkw線段樹的思想是直接找到乙個大區間對應的小區間 由於是自底向上的,所以常數很小 統計的力量 其實我覺得,真正難寫的是區間修改 比如現在造一顆線段樹,支援區間求和,區間修改 zkw線段樹有兩種做法 一是維護神奇的字首和的字首和 二是沿用遞迴版線段樹的思路,在區間上打標記,然...