線段樹補 (挑戰的方法)

2021-08-21 14:16:48 字數 1503 閱讀 8390

話說其實之前在計蒜客學線段樹就覺得費勁,弄了挺久好不容易算是理解了,這學長一說結果和我學的其實不大相同,就是少了乙個建樹的過程,或者說我的建樹不大正經(hhh;然後我也懶得再去試著寫這種,我就按之前那麼寫的的就ok了,然後當我在《挑戰程式設計》這本書看相關線段樹的章節時,說實話也就是看看,看了一眼覺得和我的**差異比較大,就不打算看了,當我去計蒜客學習樹狀陣列的時候,我:啊哈?懵了,這啥,然後我又翻開挑戰,我注意到貌似挑戰的樹狀陣列介紹好像和線段樹很貼近,比較容易接受,所以在此把挑戰的思路學習一下:

(不得不說,挑戰的線段樹**還是很新奇嚴謹的,感覺不寫個部落格和樣板例題比較容易忘

關於一些前面已經介紹過的線段樹概念也就不提了  直接說差不多思路,其實我也是根據**在紙上寫了個例子試了試

哦對了 書上介紹的這個是線段樹的rmq  range minimum query  

就是給定數列a0,a1,a2...an-1;

操作一:給出s,t  求as,as+1,as+2...at的最小值

操作二:更新值

關於查詢:

如果所查詢的區間和當前節點對應的區間完全沒有交集,那麼就返回乙個不影響答案的值(比如int_max應該就是無窮大吧

如果所查詢的區間完全包含了當前節點對應的區間,直接返回當前節點的值

以上都不滿足,就是最主要的對左右子結點遞迴處理,返回左右子節點中的最小值

複雜度:

假如是n個元素,也就是說數列有n個,那麼節點數是n+n/2+n/4+...=2n,所以線段樹的初始化的時間複雜度和總的空間複雜度都是o(n)

那啥。。。。看圖  我再上**片段

const int maxn=1<<17  //2的17次方

int n, dat[maxn*2-1] //儲存線段樹的全域性陣列

void init( int n_)

}int query ( int a,int b, int l, int r)

}

假如是之前我畫的那個樣例的樹圖,從第一步初始化開始

圖中一共4個元素,7個節點,而初始化就是將dat[0]~dat[6]全部變為無窮大

接下來的更新值函式

舉例將第3個數賦值為24:

也即k=3,a=24;

第一步為什麼是k+=n-1;

第三個數對應的節點是節點4,一共4個數,那麼k+=n-1剛好把k變成4,

意思他在樹的節點4位置,然後將a賦值給這個節點。

而接下來的while迴圈一定要注意了 是針對於dat也就是樹從0開始用,而不是從1開始。就是向上一層更新dat值 也就是把最小值向上一層傳遞

query函式沒啥好說的 和之前差不多

//不過話說回來  不知道為什麼用這個方法去做hdu1754這種最基本的題卻做不出不知道哪兒出了問題,回頭問一下學長,然後再更,先回去睡覺了(逃,醒了得好好看看線段樹了!!!

線段樹總結 (補)

線段樹總結 昨天寫得太慢了,以致於忘了寫總結了。所以,特來補下。首先,是離散化壓縮空間,雖然,可能存在不要離散化的情況,但那主要是用於線段不長的情況下,對於比較長的線段,就需要有到離散化,把線段的端點進行排序,確定端點數後再建樹。這裡很抱歉,昨天的演算法只提到了離散化,但是實際上並沒有完成,所以對於...

ZKW線段樹 非遞迴版本的線段樹

學習和參考 下面是支援區間修改和區間查詢的zkw線段樹模板,先記下來。include include include include include include include include include include include include include include inc...

線段樹的總結

線段樹 線段樹是擅長處理區間的一棵完美二叉樹 所有的葉子的深度相同,並且每個節點要麼是葉子要麼是有兩個兒子的樹 樹上的每個節點都維護乙個區間,根維護的是整個區間,每個節點維護的是父親的區間二等分後的其中乙個子區間。線段樹的修改分為區間修改和點修改,查詢分為點查詢和區間查詢。初始化函式 void in...