題解/算法 {F - Second Largest Query}
@LINK: https://atcoder.jp/contests/abc343/tasks/abc343_f
;
錯誤: 用莫隊是會超時的; 因爲Add/Delete
函數 你做不到O(1)
用平衡樹維護 他的時間是logN
的; (通過了1/5
的數據 其他都超時了);
錯誤: 用綫段樹套平衡樹 也會超時, 因爲Initialize
的耗時是2e5 * logN * logN = 1e8量級
修改和查詢的耗時是logN*logN
再乘上查詢次數 也是1e8量級
(通過了1/2
數據);
之所以你會選擇樹套樹這種綫段樹, 你是犯了@LINK: https://editor.csdn.net/md/?articleId=126806166
這個錯誤… 你認爲: 修改操作A[x]=d
來更新數據域 所以數據域就必須維護區間裏的所有元素; 這種想法是錯誤的… 因爲非葉子節點的數據域 是通過Update_nonLeaf
即兩個兒子的數據域來更新的 而不是通過A[x]=d
這個修改操作來進行的!
因此 使用普通綫段樹 就可以了, 如果一時想不明白綫段樹的精髓 那麽你只需要去考慮 只要你能滿足Update_leaf, Update_nonLeaf
這兩個函數 那麽這個綫段樹就是合理的! 其他的函數Initialize, Modify, Query
都不用管他!!!
void Update_leaf( const __ArrayType_ & _val){ // 執行底層數組`Arr[i]==val` 更新葉子節點`[i,i]`對應的*數據域*;
ASSERT_SYSTEM_( Interval.first == Interval.second);
Ma = _val, Cont = 1;
Ma1 = -1, Cont1 = 0;
}
void Update_nonLeaf( const __Data_ & _lef, const __Data_ & _rig){
ASSERT_SYSTEM_( _lef.Interval.second+1 == _rig.Interval.first);
Interval = {_lef.Interval.first, _rig.Interval.second};
std::map< int, int> A;
A[ _lef.Ma] += _lef.Cont;
A[ _lef.Ma1] += _lef.Cont1;
A[ _rig.Ma] += _rig.Cont;
A[ _rig.Ma1] += _rig.Cont1;
auto last = A.rbegin(); Ma = last->first; Cont = last->second;
++ last; Ma1 = last->first; Cont1 = last->second;
}