四月之線段樹の從入門到入土

4.2 點擊進入新世界
題意:有n個人,在插隊。輸出最後隊伍中,所有人的val 。
solution:
因爲是插隊,每個後來者居上都會影響前面的賦值,所以可以採用逆序更新;
用 val維護權值,pos維護位置,s維護區間空位;
由於他的位置開始,而我個人習慣從1開始,所以預處理的時候pos記得++。
如果可以放的位置沒有超過左邊空位數目,那麼可以往左子樹遞歸,不然往右子樹遞歸。
重點在於往右子樹遞歸時要減去左區間的空位數。

if(pos<=s[kl]) add(lson,pos,val);
else add(rson,pos-s[kl],val);

詳細代碼

4.3 點擊進入新世界
題意:1表示有連續x人住房,輸出這次住房的l座標,2表示[l,r)的人退房。
solution:
lazy 選三種狀態,0表示無人居住,-1表示這個區間不是完整的,1表示已經住滿。
常見的區間合併,就要注意lsum和rsum數組的更新,以及msum數組的維護。
msum[k] = max( lsum[kr]+rsum[kl] , max ( msum[kl] , msum[kr] ) )

講一下自己需要注意的點,就是處理區間合併的問題,總是分不清lr和LR的區別,
所以下次統一用一個結構體來寫區間合併的問題。
區間合併其實很套路,但是爲什麼總是要寫這麼久呢? 反省一下。

詳細代碼

4.4 點擊進入新世界
題意:有h行,w寬度,n張報紙,每張報紙寬度a[i],求每張報紙能放在第幾行。
solution:
每個節點維持左右子區間的最大空位。
重點在於query的時候注意值的up,而不是直接return query。

 ll ans = s[kl]>=x ? query(kl,l,mid,x):query(kr,mid+1,r,x);
 s[k]= max(s[kl] ,s[kr]);
 return ans;

詳細代碼

4.5 點擊進入新世界
題意:區間連續嚴格遞增子段長度。
solution:
裸題,用mid和mid+1來標識,這樣的話就可以完成區間的銜接。
注意詢問區間時左右兒子和本區間片段比較,例如6,6 就要注意長度不能夠超過1。

ll query(ll k,ll l,ll r,ll L,ll R){
    if(l>=L&&r<=R) return s[k];
    ll mid = l+r >>1;
    ll ans=0;
    if(L<=mid) ans=max(ans,query(kl,l,mid,L,R));
    if(R>mid) ans=max(ans,query(kr,mid+1,r,L,R));
    if(a[mid]<a[mid+1]) ans=max(ans,min(mid-L+1,sr[kl])+min(R-mid,sl[kr])); //防止區間貢獻重複
    return ans;
}

詳細代碼


我攤牌了,不玩線段樹了,玩字符串了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章