这是该问题的困难版本。唯一不同的是,在这个版本中,n≤200000。只有当两个版本的问题都解决了,你才能进行黑客攻击。
有n个药水排成一行,最左边是药水1,最右边是药水n。每种药水在喝下后都会使你的健康状况增加ai。ai可以是负数,这意味着该药水会减少你的健康状况。
你开始时健康状况为0,你将从左到右,从第一个药水走到最后一个。在每个药水处,你可以选择喝下它或忽略它。你必须确保你的健康状况始终是非负值。
你能喝的最大药水数量是多少?
输入
第一行包含一个整数n(1≤n≤200000)--药水的数量。
下一行包含n个整数a1, a2, .... ,an (-109≤ai≤109),代表喝完药水后的健康变化。
输出
输出一个整数,即你能喝的最大药水数量,而你的健康状况不会变成负数。
例子
inputCopy
6
4 -4 1 -3 1 -3
outputCopy
5
注意
在这个例子中,你可以通过服用药水1、3、4、5和6喝下5瓶药水。不可能喝完所有的6种药水,因为你的健康状况会在某一时刻变成负数。
题解:
我们默认每次选的时候都选cnt++,并把a[i]存到小根堆中,如果此时s < 0,我们就减去小根堆里,最小的元素,并弹出,cnt--
可以后悔的选取方法,很新奇一种思路,一旦与不符合条件,就减去之前加过最小的,
#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
#define int long long
int a[200050];
int b[200050];
void solve()
{
int n;
cin >> n;
int f = 0;
priority_queue<int,vector<int>,greater<int>> q;
for(int i = 1;i <= n;i++)
{
cin >> a[i];
}
int cnt = 0;
for(int i = 1;i <= n;i++)
{
f += a[i];
q.push(a[i]);
if(f < 0)
{
cnt--;
f -= q.top();
q.pop();
}
cnt ++;
}
cout << cnt;
}
//3 -2 3
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int t = 1;
// cin >> t;
while(t--)
{
solve();
}
}