代码源每日一题
现在上帝有一个空集合,现在他命令你为他执行下列三种操作 nn 次,他每次会给你一个操作类型 opop。
操作1:向集合中插入一个整数 xx;
操作2:将集合中所有的数加上 xx;
操作3:输出集合中最小的数,并从集合中将他删除,如果存在多个最小的整数,任意选择一个即可;
输入描述
第一行输入一个整数 nn;
接下来的 nn 行,每行的输入如下所示。第一个数代表 opop,如果 op=1op=1 或 op=2op=2,第二个数代表 xixi:
11 xixi
22 xixi
33
输出描述
如果 op=3op=3,请输出集合中的最小值。
样例输入
7
1 2
1 1
3
1 3
2 5
3
3
样例输出
1
7
8
数据范围
2≤n≤1062≤n≤106, 1≤xi≤1012
思路:首先我们先考虑操作2,如何能够快速对区间进行修改:线段树,差分,使用变量先减后加。线段树:太难我不会。差分(部分区间最好的方法):其中有删除操作,不利于全部遍历sum数组,而且不知道大小。添加变量进行先减后加(而且增加是全体增加):我们可以使用添加一个变量add,记录一共增加的大小,只要在输出时加上add即可,但是先增加过之后在输入一个数,如果后面后添加的数也加add是不是就错了(偏大了,如何将他变小呢?),现在提供一种新的思路,让它在输入时就减去之前的add,输出加上add时就刚好能够抵消了。
现在考虑操作3,如何输出最小值呢?这里使用优先队列来解决,优先队列会按照你的规定从小到大,或者从大到小自动排序。(greater为逐渐增大,less为逐渐减小)。
优先队列模板:
priority_queue<int,vector<int>,greater<int> >q;//从小到大排序
priority_queue<int,vector<int>,less<int> >q;//从大到小排序
完整代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
priority_queue<int,vector<int>,greater<int> >q;//从小到大排序
//priority_queue<int,vector<int>,less<int> >q;//从大到小排序
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
scanf("%lld",&t);
int add=0;
while(t--)
{
int op;
scanf("%lld",&op);
if(op==1)
{
int x;
scanf("%lld",&x);
q.push(x-add);
}
else if(op==2)
{
int x;
scanf("%lld",&x);
add+=x;
}
else
{
printf("%lld\n",q.top()+add);
q.pop();
}
}
return 0;
}