ソリューションCF1398 E \ mathrm {CF1398E}C F 1 3 9 8 E
トピックの意味
S ol \ mathrm {Sol} S O L
これは私が最近やったより難しいEEだと思いますE、詳細がたくさんあります
ここではAAと仮定しますAは2倍にできる呪文、BBB反対
私たちは最初に貪欲な考えを持っていますすべてのAAです大きなウェイトを一致させると、使用しようとAA最初にA自体の重量は、2倍の寄与を生み出すことができないため、可能な限り小さくなります。
セットを使用してAAを維持することを検討しますウェイトのセット(どちらも繰り返されないことが保証されており、操作を簡単にするために小さいものから大きいものにソートされています)。そして今ssがあるとしましょうs2つのAAA次にs1s1を数えますsの1手段前回のSSをs大きな重みの合計、s 2 s2s 2は、前のs + 1 s +1を意味しますs+1つの大きな重みの合計、およびSSSは、現在の所有権の値の合計です。
そこで、分類して議論します。
-
現在のAAを想定A mimiの最小値M私の所有値の順位≤S \ sの当量≤sの場合、寄与は(S + pre 2 − mi)(S + pre2-mi)です。(S+p r e 2−m i )。具体的には、この最小値はAAですAの始まりとsss2つのAAAとそれ自体接続して使用され、端部におけるBBB。
-
他の状況への寄与は(S + pre 1)(S + pre1)です(S+p r e 1 )つまり、1つずつ一致させることができます。
重みのランク付けについては、バランスツリーを直接維持できます(div2Eはバランスツリー/ファッドを使用します。fhqを祝福します)
時間の複雑さ:O(nlogn)O(n \ log n)O (nlo gn )
コード\ mathrm {Code} C O D E
const int N=1e6+5;
int n,m,noden,tot,cnt,pre1,pre2;
int ans,sum;
set<int> S;
struct node
{
int lc,rc,rnd,val,sz;
}a[N];
struct fhq{
#define new NEW
int rt;
void pushup(int x){
a[x].sz=a[a[x].lc].sz+a[a[x].rc].sz+1;
}
int new(int val){
a[++noden]=(node){
0,0,rand(),val,1};
return noden;
}
void split(int now,int val,int &x,int &y){
if(!now){
x=y=0;
return ;
}
if(a[now].val>=val){
x=now;
split(a[now].rc,val,a[now].rc,y);
}
else{
y=now;
split(a[now].lc,val,x,a[now].lc);
}
pushup(now);
}
int merge(int x,int y){
if(!x||!y) return x|y;
if(a[x].rnd<a[y].rnd){
a[x].rc=merge(a[x].rc,y);
pushup(x);
return x;
}
else{
a[y].lc=merge(x,a[y].lc);
pushup(y);
return y;
}
}
int getk(int x,int k){
if(!k||k>a[rt].sz) return 0;
for(;;){
if(k<=a[a[x].lc].sz) x=a[x].lc;
else if(k==a[a[x].lc].sz+1) return x;
else{
k-=a[a[x].lc].sz+1;
x=a[x].rc;
}
}
}
void insert(int val){
int x,y;
split(rt,val,x,y);
rt=merge(merge(x,new(val)),y);
}
void Del(int val){
int x,y,z;
split(rt,val,x,z);
split(x,val+1,x,y);
y=merge(a[y].lc,a[y].rc);
rt=merge(merge(x,y),z);
}
int Find(int val){
int res,x,y;
split(rt,val+1,x,y);
res=a[x].sz+1;
rt=merge(x,y);
return res;
}
int Kth(int rank){
return a[getk(rt,rank)].val;
}
}T;
signed main()
{
io.read(n);
for (;n--;)
{
int op,x;
io.read(op),io.read(x);
int y=abs(x);
sum+=x;
int rk=T.Find(y);
if(x>0)
{
if(rk<=cnt) pre1+=(y-T.Kth(cnt));
if(rk<=cnt+1) pre2+=(y-T.Kth(cnt+1));
T.insert(y);
if(op==1)
{
cnt++;
pre1+=T.Kth(cnt);
pre2+=T.Kth(cnt+1);
S.insert(y);
}
if(T.Find(*S.begin())==cnt) ans=sum+pre2-*S.begin();
else ans=sum+pre1;
}
else
{
if(rk<=cnt) pre1-=(y-T.Kth(cnt+1));
if(rk<=cnt+1) pre2-=(y-T.Kth(cnt+2));
T.Del(y);
if(op==1)
{
pre1-=T.Kth(cnt);
pre2-=T.Kth(cnt+1);
cnt--;
S.erase(y);
}
if(cnt&&T.Find(*S.begin())==cnt) ans=sum+pre2-*S.begin();
else ans=sum+pre1;
}
io.write(ans);
puts("");
}
return 0;
}