题解 CF1398E 【Two Types of Spells】

题解 C F 1398 E \mathrm{CF1398E} CF1398E

题目意思

题目传送门

S o l \mathrm{Sol} Sol

感觉这是最近我做过比较难的 E E E 啦,细节真的草鸡多

我们在这里假定 A A A 为能翻倍的法术, B B B 相反

我们首先有个贪心思路就是每个 A A A 尽量配对大的 权值,并且第一个使用 A A A 的本身权值尽可能小,因为其不能产生翻倍贡献。

我们考虑用 set 维护 A A A 权值的集合(既保证不重复也从小到大排序便于操作)。并且假设现在有 s s s A A A 那么我们计 s 1 s1 s1 表示前 s s s 大的权值和, s 2 s2 s2 表示前 s + 1 s+1 s+1 大的权值和,以及 S S S 为当前所有权值的总和。

于是我们分类讨论:

  • 假设当前 A A A 的最小值 m i mi mi 在所有权值的排名 ≤ s \leq s s 那么贡献即为 ( S + p r e 2 − m i ) (S+pre2-mi) (S+pre2mi)。具体地就是把这个最小的作为 A A A 的开头然后 s s s A A A 本身连接使用,最后带一个 B B B

  • 对于其他情况的贡献即为 ( S + p r e 1 ) (S+pre1) (S+pre1) 即一个配一个即可。

对于权值的排名我们直接平衡树维护一下就好了(div2E 就要用平衡树/fad,直接贺了个fhq就好了)

时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)

C o d e \mathrm{Code} Code

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;
}
			
			
			

猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/108019011