線段樹 樹狀陣列 總結

2021-08-09 05:39:49 字數 3128 閱讀 5438

前言在對這三個資料結構進行了粗淺的學習之後,博主發現資料結構的世界是多麼的美妙。

然後在博主的專業作死技能加持之下,三個資料結構的大戰一觸即發……

對於某些題目(如,單點更新並且查詢區間和),那麼這個時候,我們會發現用樹狀陣列也十分吃香,畢竟這正是樹狀陣列所擅長的!它的時間複雜度均為o(log(n)),相比於線段樹,它的空間複雜度尤其小得多。

void update(int target,int

pos,int val)

int query(int target,int

pos)

然後接著,zkw線段樹(%%%%)對此也是再擅長不過了,看起來十分的歡快。

畢竟是非遞迴的,常數小,在大部分情況下,可以大大加快操作速度。

思想

單點修改:先通過n直接找到葉子節點,然後再向上更新父親節點。

區間查詢:為了避免錯誤,我們在找葉子節點之前,先轉閉區間為開區間獲取指標。左邊的指標如果是父親的左子樹就累加其右子樹的答案,右邊的指標如果是父親的右子樹就累加左子樹的答案。直到兩指標的父親節點相同。

為了更好的理解,建議手動模擬~

void update(int pos,int val)

void query(int l,int r)

}

但是同時,我們也知道,線段樹更新、查詢等操作的複雜度也為o(log(n))。但是線段樹的常數較大。尤其對於這些比較入門的題目的時候,**量會比較大,也就使得我們更容易出錯。儘管如此,我們還是貼一下它操作的**,以示敬意。

inline void pushup(int rt)

inline void pushdown(int ln,int rn,int rt)

void update(int l,int r,int l,int c,int rt)

int m=(l+r)>>1;

if(l<=m)

update(l,m,l,c,rt<<1);

else

update(m+1,r,l,c,rt<<1|1);

pushup(rt);

}

int query(int l,int r,int l,int r,int rt)

由此可見,在應對一些簡單問題的時候,線段樹不一定是最好的選擇。由於其在第一部分,時間及空間複雜度的優異表現,於是各路神犇就對其作出了更強的改進。

dalao says:亂寫能ac,暴力踩標程

思想

以下的update(),query()函式的含義同上。

假設原陣列為a,利用差分的思想處理出s陣列,即s[

i]=a

[i]−

a[i−

1];

那麼顯然,我們可以得到這樣的式子:a[

i]=∑

ij=1

s[j]

則我們會發現 ∑i

=1na

[i]=

∑i=1

n∑j=

1is[

j]我們再展開一下,就會變成這樣,乙個三角形!

補全為矩形,然後減去補上的三角形,繼續化簡: ∑i

=1na

[i]=

n∑i=

1ns[

i]−∑

i=1n

(i−1

)s[i

] 將後面的的∑n

i=1(

i−1)

s[i]

作為si進行維護,即si

[i]=

(i−1

)s[i

] 然後就可以做到區間更新與修改了!

scanf("%d",&type);  

if(type==1)//[l,r]+v

else//[l,r]->sum

**中一些變數的含義:

ln:s一路走來已經包含了幾個數

rn:t一路走來已經包含了幾個數

x:本層中包含的數

思想

lazy陣列依然是懶惰標記,不過利用了差分的思想,化絕對為相對。因此,在更新與查詢的時候,[l,r]所對應的區間上公升到父親相同之後,還要繼續向上一直上公升到根節點。

void update(int l,int r,int c)  

for(;s;s>>=1,t>>=1)

}int query(int l,int r)

for(;s;s>>=1,t>>=1)

return ans;

}

相對來說,普通線段樹應對的比較從容,**量也沒有增加太多,但依舊是最大的……

inline void pushup(int rt)

inline void pushdown(int ln,int rn,int rt)

void update(int l,int r,int l,int r,int c,int rt)

int m=(l+r)>>1;

if(l<=m)

update(l,m,l,r,c,rt<<1);

if(m1,r,l,r,c,rt<<1|1);

pushup(rt);

}int query(int l,int r,int l,int r,int rt)

由此可見,普通線段樹相對於樹狀陣列與zkw線段樹來說,更加靈活多變,甚至能夠應對更加複雜的情況而游刃有餘。樹狀陣列:如果能用的話,在時間、空間複雜度上估計都可以暴踩線段樹(用了都說好)

zkw線段樹:常數小,性質多,跑的也的確比普通線段樹要快得多,但似乎應用上還有一些侷限性,不一定適用於所有的題目。感覺很強的樣子,只不過要搞懂它的精髓可能還需要時間……

普通線段樹:很靈活,能夠應對複雜多變的題目,到底是經典。

線段樹與樹狀陣列學習總結 線段樹

點動成線 那麼就是說一條線段可以分成若干個點,再想想我們最常用的一維陣列,構成陣列的是乙個個的變數,如果把變數看成乙個個點,那麼陣列就是一條線了!而線段樹,就是一棵由線段構成的二叉樹,每個結點都代表一條線段 a,b 也就是我們前面說的一串變數 非葉子的結點所對應的線段都有兩個子結點,左兒子代表的線段...

線段樹,樹狀陣列,主席樹

樹狀陣列 主席樹 包括無修改和可修改。用乙個滿二叉樹 葉子節點可以為空 來維護乙個連續陣列,整個樹的所有葉子節點從左到右表示整個陣列,每個非葉子節點表示其所有葉子的集合所描述的乙個連續子陣列的某一特性 最小值,最大值等 可以在logn的複雜度內實現對任意連續欄位的給定特性的查詢 最小值等 可以在lo...

線段樹 劃分樹 樹狀陣列

線段樹 利用陣列來維護乙個類似字首和的區間和 在查詢的時候查這個區間陣列 特殊操作 有延時標記 在區間陣列上增加基本不改變原來陣列 以達到節省時間的目的 樹狀陣列 和線段樹類似 乙個用乙個陣列維護類似字首和的東西 但 是 它維護的是乙個用二進位制表示的字首和 舉個例子 1是1 2是1 2 3是3 4...