CF1398E Two Types of Spells 题解
如果当前有 \(sum\) 个可以翻倍,那么考虑可不可以让前 \(sum\) 大的都翻倍。可以当且仅当这 \(sum\) 大的数不全能翻倍下一个数。如果全都能翻倍下一个数,那只能牺牲第 \(sum\) 大的数,最后可以再翻倍一个第 \(sum+1\) 大的。
然后有多次删除插入就用 set
维护一下就行了。
点击查看代码
std::set<int> t[2],is;
int n,cnt[2];
ll sum[2];
inline void update(int id){
int x=(id?*t[id].begin():*t[id].rbegin());
bool op=is.count(x);
sum[id]-=x,sum[id^1]+=x;
t[id].erase(x),t[id^1].insert(x);
cnt[id]-=op,cnt[id^1]+=op;
}
int main(){
//file();
read(n);
while(n--){
int op,x;read(op),read(x);
if(x>0){
sum[0]+=x;
t[0].insert(x);
cnt[0]+=op;
if(op) is.insert(x);
}
else{
x=-x;
int id=(t[1].count(x));
sum[id]-=x;t[id].erase(x);cnt[id]-=op;
if(op) is.erase(x);
}
int tot=cnt[0]+cnt[1];
while(t[1].size()<tot) update(0);
while(t[1].size()>tot) update(1);
while(!t[0].empty()&&!t[1].empty()&&*t[0].rbegin()>*t[1].begin()) update(0),update(1);
ll ans=sum[0]+2*sum[1];
if(tot&&cnt[1]==tot){
ans-=*t[1].begin();
if(!t[0].empty()) ans+=*t[0].rbegin();
}
println(ans);
}
return 0;
}