P4314 CPU監控
阿新 • • 發佈:2020-07-27
線段樹標記好題
這題要支援區間加,區間賦值,區間查最大值,區間查歷史最大值。
直接用線段樹維護區間最大值和歷史最大值,再打倆 \(tag\) 是不夠的,因為倆 \(tag\) 不一定能夠及時下傳至葉子節點。
因此我們需要額外多打倆 \(tag\):(從上次更新以後)加法標記的歷史最大值,(從上次更新以後)賦值標記的歷史最大值。並且我們保證賦值操作絕對優於加法操作,即原有加法標記,再賦值以後會取消加法標記(但是不會清空加法標記的歷史最大值);原有歷史標記,再加法就直接視為賦值為某個值的操作。
因此,我們在操作標記的時候要對有賦值標記的情況進行特殊處理。
需要注意的是,下放標記的時候,我們需要先下放加法標記,再下放賦值標記
賦值標記不需要管 \(now~max\) 是否正確,因為用不到。
關鍵程式碼:
//vst : 是否存在賦值標記 inline void push_set(int cur, int v, int hv) { if (!cur) return ; mx[cur] = v, MAX(hmx[cur], hv); if (vst[cur]) MAX(hstag[cur], hv), stag[cur] = v;//Attention!! else vst[cur] = true, stag[cur] = v, hstag[cur] = hv; atag[cur] = 0; } inline void push_add(int cur, int v, int hv) { if (!cur) return ; MAX(hmx[cur], mx[cur] + hv), mx[cur] += v;//Attention!!! <-error if (vst[cur]) push_set(cur, stag[cur] + v, stag[cur] + hv); else MAX(hatag[cur], atag[cur] + hv), atag[cur] += v; } inline void pushdown(int cur) { if (vst[cur] && atag[cur]) exit(-1); push_add(ls[cur], atag[cur], hatag[cur]), push_add(rs[cur], atag[cur], hatag[cur]), atag[cur] = hatag[cur] = 0; if (vst[cur]) { push_set(ls[cur], stag[cur], hstag[cur]), push_set(rs[cur], stag[cur], hstag[cur]), stag[cur] = hstag[cur] = 0; vst[cur] = 0; } }