Potions
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
This is the hard version of the problem. The only difference is that in this version n≤200000. You can make hacks only if both versions of the problem are solved.
There are n potions in a line, with potion 1 on the far left and potion n on the far right. Each potion will increase your health by ai when drunk. ai can be negative, meaning that potion will decrease will health.
You start with 0 health and you will walk from left to right, from first potion to the last one. At each potion, you may choose to drink it or ignore it. You must ensure that your health is always non-negative.
What is the largest number of potions you can drink?
Input
The first line contains a single integer n (1≤n≤200000) — the number of potions.
The next line contains n integers a1, a2, … ,an (−109≤ai≤109) which represent the change in health after drinking that potion.
Output
Output a single integer, the maximum number of potions you can drink without your health becoming negative.
Example
input
6
4 -4 1 -3 1 -3
output
5
Note
For the sample, you can drink 5 potions by taking potions 1, 3, 4, 5 and 6. It is not possible to drink all 6 potions because your health will go negative at some point
题目大意:
输入一个n,接下来有n个数字,初始生命值为0,第 i 个数字表示喝下该药水后生命值会增加ai (可以是负的) 从左往右开始喝,你需要每时每刻使生命值保持为非负数,输出最多可以喝多少瓶药水。
解题思路:
带悔贪心,分析这道题,维护答案res和当前生命值sum,如果当前药水权值为非负数,那就必须喝,对于每一个输入的负数,用优先队列存一下绝对值权值最大的数(即最小的负数),每次res++, sum += x,如果x为负则存一下,如果喝下这瓶药生命值负了,那么res–,之后取队头,sum+=top,删除堆顶,思想是每次只喝下扣血少的药(可以不喝),取队头的操作即前面扣血最多的药不喝,来喝这瓶扣血少的药。时间复杂度O(nlogn)。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
int n;
LL sum, res;
priority_queue<LL, vector<LL>, less<LL> > q;
int main() {
cin >> n;
for (int i = 1; i <= n; i ++) {
LL x;
cin >> x;
sum += x;
res ++;
if (x < 0) q.push(-x);
if (sum < 0) {
res --;
sum += q.top();
q.pop();
}
}
cout << res << endl;
return 0;
}