Educational Codeforces Round 87 (Rated for Div. 2)D.Multiset 卡内存的修改数组

文章讲述了作者在Codeforces竞赛中遇到内存超限问题,通过使用树状数组(线段树)存储出现次数并实现前缀和操作来解决题目,最终成功优化内存消耗。
摘要由CSDN通过智能技术生成

Problem - 1354D - Codeforces

我被卡了:

这道题看到multiset我还真写multiset,结果内存超限。

当然能想到想同的数存到一块,所以用了map,结果还超,诶呦:

set肯定比map大滴,这里可能刚超就结束了,事实上可能占用更大。

思路:

本题是得用树状数组或者线段树存出现次数做,而且内存足够多。

我是用的类构造的线段树。

初始一个1e6的数组,构造里有1e6的这个数组和树状数组,比3e6大,粗算一下吧,4e6 * 4字节 = 16e6 ,也就是16MB,也不超28MB。

————

存出现次数,树状数组记录的前缀和,所以可以二分找到第几个数。

代码:

这个类板子就是我的树状数组1

template<class T>
class BIT//Binary Indexed Tree
{
public:
	ll n;//a的大小
	vector<T>a;//原数组
	vector<T>c;//树状数组
	ll lowbit(ll a)
	{
		return a & -a;
	}
	T getsum(ll i)
	{
		T sum = 0;
		while (i > 0)
		{
			sum += c[i];
			i -= lowbit(i);
		}
		return sum;
	}
	void add(ll i, T v)
	{
		while (i <= n)
		{
			c[i] += v;
			i = i + lowbit(i);
		}
	}
	BIT(vector<T>_a)
	{
		a = _a;
		n = a.size() - 1;
		c = vector<T>(n + 1);
		//直接把树建好
		for (ll i = 1; i <= n; i++)
		{
			add(i, a[i]);
		}
	}
};

void solve(int casen)
{
	int n, m;
	cin >> n >> m;
	vector<int>arr(1000002);
	BIT<int> demo(arr);
	for (int i = 1; i <= n; i++)
	{
		int tmp;
		cin >> tmp;
		demo.add(tmp, 1);
	}


	for (int i = 1; i <= m; i++)
	{
		int tmp;
		cin >> tmp;
		if (tmp < 0)
		{
			tmp = -tmp;
			//二分找第tmp个
			int l = 1, r = 1000000;
			while (l < r)
			{
				int mid = l + (r - l) / 2;
				if (demo.getsum(mid) >= tmp)
					r = mid;
				else
					l = mid + 1;
			}
			demo.add(l, -1);//有人给tmp减
		}
		else
		{
			demo.add(tmp, 1);
		}
	}
	int l = 1, r = 1000000;
	if (demo.getsum(1000000) == 0)
	{
		cout << 0;
		return;
	}

	while (l < r)
	{
		int mid = l + (r - l) / 2;
		if (demo.getsum(mid) > 0)
		{
			r = mid;
		}
		else
			l = mid + 1;
	}
	cout << l;

}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	//cin >> t;
	for (int i = 1; i <= t; i++)
	{
		solve(i);
	}
	return 0;
}

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值