题解CF1398E【2種類の呪文】

ソリューション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 2m i 具体的には、この最小値はAAですAの始まりとsss2つのAAAとそれ自体接続して使用され、端部におけるBBB

  • 他の状況への寄与は(S + pre 1)(S + pre1)ですS+p r e 1 つまり、1つずつ一致させることができます。

重みのランク付けについては、バランスツリーを直接維持できます(div2Eはバランスツリー/ファッドを使用します。fhqを祝福します)

時間の複雑さ:O(nlog⁡n)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;
}
			
			
			

おすすめ

転載: blog.csdn.net/wangyiyang2/article/details/108019011