取球游戏(C++)[堆]

题目:

Description

小J有很多空白的球和一个袋子。最初,袋子是空的。

小J将会作出Q个操作,具体如下:

操作1 在白球上写一个数字X_i然后扔进袋子里;

操作2 将袋子里所有球的数字都加上X_i

操作3 输出袋子里最小的数字并把它从袋子里取出。

Q<=2*100000

x_i<=1e9

Format

Input

见样例

Output

针对每个操作3,输出结果

Samples

输入数据 1

5
1 3
1 5
3
2 2
3

输出数据 1

3
7

思路:

从”操作1“和 “操作3”不难看出,这道题要用来储存元素

但是第二个操作就有些棘手了

思路1:如果我们用每次将堆里存的元素取出来,再统一加上一个数,在全部装进堆里:

假设有堆里n个元素

每次操作的时间复杂度大概是O(2*n*log2(n))

(注:堆的删除与插入的时间复杂度都是O(log2(n))的)

结合数据范围Q<=2*100000,这种方法是绝对过不了的

 当时我们队里的人都懵B了,以为教练出错题了

思路2:这时我们的教练告诉了我们一个时间复杂度O(1)的操作:

在上一个算法的基础上我们可以开一个懒标记lazy

针对每个“操作2”,我们可以在lazy加一个x_i

等到执行“操作3”时,再在弹出的堆顶加上一个lazy就行了

可是这样做连后面进来的元素也会被打上标记

这时我们可以这样做:
针对每个“操作1”:将每个读入的x_i,先减去一个lazy,再打入堆中,这样就可以将前面的标记抵消掉。

Code:

#include<bits/stdc++.h>
using namespace std;
//小根堆,每次弹出堆中最小值 
priority_queue<long long, vector<long long>, greater<long long> >a;
//操作 
int operate;
//懒标记 
long long lazy = 0;
long long num;
long long ans = 0;
int n;
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &operate);
		if (operate == 1)
		{
			scanf("%lld", &num);
			//插入 num-lazy 抵消前面的操作 
			a.push(num - lazy);
		}
		if (operate == 2)
		{
			scanf("%lld", &num);
			//标记加上num 
			lazy += num;
		}
		if (operate == 3)
		{
			//输出别忘了加上标记 
			printf("%lld\n", a.top() + lazy);
			a.pop();
		}
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值