對於以前做的區間合并線段樹頗有微詞,對於大神們使用三個數組來記錄節點的情況很是不解。對於當前點,只需要能提供所需的w長度區間即可向下進行判斷,左子樹優先提供,左右子樹合并提供,右子樹最後提供,否則輸出不可行。
故我認為只需要一個記錄當前節點的情況的數組即可,不需要三個數組,故用一個數組實際編寫了代碼。後發現此法是不行的.... 首先判斷左右子樹能否提供的問題,lsum+rsum>=w則返回m-lsum+1,這樣用三個數組很方便,若用一個數組會有很多bug,因為一個數組只是記錄自己的情況:左右子樹提供給自己的東西。而沒有考慮區間的連續性。舉例來說:1-10的線段樹,左子樹右子樹分別提供4,但是5,6兩點已經被占,這時要提供8長度的區間顯然不可能,但是只用一個數組會出現可行的情況而且答案是2.為何要使用三個數組?因為我對這些數組各自的功能不是很清楚,現在來看,lsum與rsum有各自的用處。lsum,rsum各自記錄當前點向左向右的連續區間各多長,也就是說這兩個數組實際上起的作用就是用來判斷區間連續與否。
void PushUp( int rt,int m ) { lsum[rt]=lsum[rt<<1]; //當前lsum直接取左子樹的lsum[]值 rsum[rt]=rsum[rt<<1|1]; //當前sum直接取右子樹的rsum[]值 if( lsum[rt]==(m-(m>>1)) )lsum[rt]+=lsum[rt<<1|1];//若左子樹是滿的,則向右拓展 求和 if( rsum[rt]==m>>1 )rsum[rt]+=rsum[rt<<1];//若右子樹是滿的,則向左拓展 求和 msum[rt]=max( lsum[rt<<1|1]+rsum[rt<<1],max( msum[rt<<1],msum[rt<<1|1]) ); //當前msum的值為左右子樹中空閑點,和 左子樹的右邊和右子樹的左邊的和中最大值 }
合并區間的重要操作就在於PushUp操作中,其他的地方lsum與rsum用法相同,共同更新,這也是我產生錯覺的原因。看來對於理解這些演算法真的很是重要啊~ 我果然還是太弱了!加油!!