题意
每个魔法都有自己的伤害,魔法1是加倍魔法,可以加倍后一个魔法的伤害,魔法0是普通魔法,给出q个更新,要求每次更新后计算魔法能造成的伤害最大值。
思路
设加倍魔法数量为k,权值线段树每次查询前k大的伤害和sumk(加倍多出来的伤害),mutiset维护魔法1和魔法2的最值,如果魔法1的最小值比魔法0的最大值大或不存在魔法0,sumk就要改变,因为至多加倍k-1个魔法1。
代码
#include
#define ll long long
#define LL long long
#define PB push_back
#define MP make_pair
using namespace std;
const int maxn=4e5+100;
const ll inf=1e18+10;
ll ID[maxn],ni,QT[maxn*4],C[maxn*4];
int n;
struct node{
ll ty,d;
}q[maxn];
void Unique(){
sort(ID+1,ID+1+n);
ni=unique(ID+1,ID+n+1)-ID-1;
}
ll getid(ll x){
return lower_bound(ID+1,ID+1+ni,x)-ID;
}
void add(ll o,ll l,ll r,ll x,ll v){
if(l==r){
QT[o]+=v;
C[o]+=ID[x]*v;
}
else{
ll mid=(l+r)>>1;
if(x<=mid) add(o<<1,l,mid,x,v);
else add((o<<1)|1,mid+1,r,x,v);
QT[o]=QT[o<<1]+QT[(o<<1)|1];
C[o]=C[o<<1]+C[(o<<1)|1];
}
}
ll sumk(ll o,ll l,ll r,ll k){
if(l==r){
if(k>=QT[o])return C[o];
else return C[o]/QT[o]*k;
}
else{
ll mid=(l+r)>>1;
ll sl=QT[o<<1],sr=QT[(o<<1)|1];
if(k<=sr) return sumk((o<<1)|1,mid+1,r,k);
else return C[(o<<1)|1]+sumk(o<<1,l,mid,k-sr);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld %lld",&q[i].ty,&q[i].d);
ID[i]=abs(q[i].d);
}
Unique();
int fire=0,light=0;
multiset<ll,greater<ll>>fireSet;
multiset<ll,less<ll>>lightSet;
ll sum=0;
for(int i=1;i<=n;i++){
ll val=q[i].d;
if(val>0)add(1,1,ni,getid(val),1);
else add(1,1,ni,getid(-val),-1);
if(q[i].ty){
if(val>0)lightSet.insert(val),light++;
else lightSet.erase(-val),light--;
}
else{
if(val>0)fireSet.insert(val),fire++;
else fireSet.erase(-val),fire--;
}
sum+=val;
ll sumk0=sumk(1,1,ni,light);
if(light&&fire){
ll li=*lightSet.begin(),fi=*fireSet.begin();
if(li>fi)sumk0+=fi-li;
}
else if(light&&!fire){
ll li=*lightSet.begin();
sumk0-=li;
}
printf("%lld\n",sum+sumk0);
}
}