P10673 【MX-S1-T2】催化剂 题解

题目传送门

前置知识

权值树状数组及应用

解法

从贪心的角度分析,当小 K 有 \(x(x \ge k)\) 个同种糖果时,将其分给 \(k\) 个小朋友时尽可能平均发是最优情况,此时产生的愤怒值为 \(x-k\)

那么,设出现次数 \(\ge k\) 的糖果分别为 \(b_{1},b_{2},b_{3}, \dots ,b_{m}\),其出现次数分别为 \(c_{1},c_{2},c_{3}, \dots ,c_{m}\),最终有 \(\sum\limits_{i=1}^{m}c_{i}-mk\) 即为所求。其中,\(\sum\limits_{i=1}^{m}c_{i}\)\(m\) 均可通过权值树状数组维护。

注意及时删除因修改造成的影响及树状数组中下标为 \(0\) 对操作中的影响。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
ll c[2][3000010],vis[3000010];
ll lowbit(ll x)
{
	return x&(-x);
}
void add(ll n,ll x,ll key,ll c[])
{
	for(ll i=x;i<=n;i+=lowbit(i))
	{
		c[i]+=key;
	}
}
ll getsum(ll x,ll c[])
{
	ll ans=0;
	for(ll i=x;i>=1;i-=lowbit(i))
	{
		ans+=c[i];
	}
	return ans;
}
int main()
{
	ll n,q,pd,x,i;
	scanf("%lld%lld",&n,&q);
	for(i=1;i<=n;i++)
	{
		scanf("%lld",&x);
		if(vis[x]!=0)
		{
			add(3000000,vis[x],-1,c[0]);
			add(3000000,vis[x],-vis[x],c[1]);
		}
		vis[x]++;
		if(vis[x]!=0)
		{
			add(3000000,vis[x],1,c[0]);
			add(3000000,vis[x],vis[x],c[1]);
		}
	}
	for(i=1;i<=q;i++)
	{
		scanf("%lld%lld",&pd,&x);
		if(pd==1)
		{
			if(vis[x]!=0)
			{
				add(3000000,vis[x],-1,c[0]);
				add(3000000,vis[x],-vis[x],c[1]);
			}
			vis[x]++;
			if(vis[x]!=0)
			{
				add(3000000,vis[x],1,c[0]);
				add(3000000,vis[x],vis[x],c[1]);
			}
		}
		if(pd==2)
		{
			if(vis[x]!=0)
			{
				add(3000000,vis[x],-1,c[0]);
				add(3000000,vis[x],-vis[x],c[1]);
			}
			vis[x]--;
			if(vis[x]!=0)
			{
				add(3000000,vis[x],1,c[0]);
				add(3000000,vis[x],vis[x],c[1]);
			}
		}
		if(pd==3)
		{
			printf("%lld\n",getsum(3000000,c[1])-getsum(x-1,c[1])-(getsum(3000000,c[0])-getsum(x-1,c[0]))*x);
		}
	}
	return 0;
}
posted @ 2024-06-29 18:40  hzoi_Shadow  阅读(21)  评论(0编辑  收藏  举报
扩大
缩小