[CF1398E] Two Types of Spells - 貪心,堆
阿新 • • 發佈:2020-11-03
Description
動態維護一個技能集合,技能分為兩種,普通技能和超級技能。所有技能會被按照一個排列執行,如果技能 \(i\) 被執行時它的前一個技能是普通技能,那麼會產生 \(w_i\) 的貢獻;如果是超級技能則會產生 \(2w_i\) 的貢獻。每次新增或刪除技能後,求當前技能集合的最大貢獻。
Solution
考慮維護三個技能集合:setNormal
表示普通技能集合,setHigh
表示當前所有技能中,貢獻較高的技能的集合,setLow
為 setHigh
的補集。
在任意時刻,我們控制 setHigh
的大小為當前超級技能的總個數,那麼 sum(*)+sum(setHigh)
基本就是答案,但需要做一點修正。
考慮如果我們希望將所有的超級技能翻倍,但這時一定有一個超級技能是不能被翻倍的(顯然我們會選擇最小的那一個)。
考慮如果我們希望翻倍的技能中有一個不是超級技能,那麼這時這些技能被同時翻倍是可以滿足的。
因此,我們從上面的近似答案中,減去當前 setHigh
集合的最小值,再加上當前 setNormal
集合的最大值,就是答案。
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 1000005; #define dbg(y, x) ; int n, countMagic, ans; set<int> setHigh, setLow, setNormal; signed main() { ios::sync_with_stdio(false); cin >> n; while (n--) { int type, value; cin >> type >> value; ans += value; if (value > 0) { if (type == 0) setNormal.insert(value); if (type == 1) countMagic++; if (setHigh.size() && value >= *setHigh.begin()) setHigh.insert(value), ans += value; else setLow.insert(value); } else { value *= -1; if (type == 0) setNormal.erase(value); if (type == 1) countMagic--; if (setLow.find(value) != setLow.end()) setLow.erase(value); else setHigh.erase(value), ans -= value; } while (setHigh.size() > countMagic) { ans -= *setHigh.begin(); setLow.insert(*setHigh.begin()); setHigh.erase(*setHigh.begin()); } while (setHigh.size() < countMagic) { ans += *setLow.rbegin(); setHigh.insert(*setLow.rbegin()); setLow.erase(*setLow.rbegin()); } int tans = ans; if (setHigh.size()) { tans -= *setHigh.begin(); if (setNormal.size()) tans += *setNormal.rbegin(); if (tans > ans) tans = ans; } cout << tans << endl; dbg("lowSize", setLow.size()); dbg("highSize", setHigh.size()); } }