先将同符号的每一段存下来,并记录前后段标号,将正数段总和记录为tot
开一个最小堆存每一段的abs值。
每次从堆中取出一个x
去掉这一段,并将左右的段与之合并再存入堆中,作为撤销或更改操作。
每次操作都会减少一段,直到段数=k就退出。
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define C (c=getchar())
using namespace std;
typedef long long ll;
inline void read(ll &x)
{
static char c;int b=1;C;
for (;!(c>='0'&&c<='9');C) if (c=='-') b=-1;
for (x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0',C); x*=b;
}
const ll N=1000005;
ll n,m,nn,cnt;
ll a[N],v[N];
ll pre[N],nxt[N];
ll ans,tot;
ll heap[2*N],ma;
ll bk[2*N];
inline ll val(ll i) {return abs(v[heap[i]]);}
inline ll F(ll i) {return (i<<1)==ma?(i<<1):(val(i<<1)<val(i<<1|1)?(i<<1):(i<<1|1));}
inline ll Swap(ll x,ll y) {swap(heap[x],heap[y]);swap(bk[heap[x]],bk[heap[y]]);}
inline void down(ll x)
{
ll i;if (x>ma) return;
for (i=x,nn;(i<<1)<=ma&&val(nn=F(i))<val(i);) Swap(i,nn),i=nn;
}
inline void up(ll x)
{
ll i;if (x>ma) return;
for (i=x;i!=1&&val(i)<val(i>>1);)Swap(i,i>>1),i>>=1;
}
inline void det(ll x)
{
Swap(x,ma);
ma--;
down(x);
up(x);
}
inline void insert(ll x)
{
heap[++ma]=x;
bk[x]=ma;
up(ma);
}
inline void Solve()
{
ll k,a,b,i;
for (i=1;i<=cnt;i++) insert(i);
while (tot>m)
{
k=heap[1];
if (pre[k]==-1)
{
if (v[k]>0) ans-=abs(v[k]),det(1),tot--;
else det(1);
pre[nxt[k]]=pre[k];
}
else if (nxt[k]==-1)
{
if (v[k]>0) ans-=abs(v[k]),det(1),tot--;
else det(1);
nxt[pre[k]]=nxt[k];
}
else
{
ans-=abs(v[k]);
a=nxt[k];b=pre[k];
pre[k]=pre[b];if (pre[b]!=-1) nxt[pre[b]]=k;
nxt[k]=nxt[a];if (nxt[a]!=-1) pre[nxt[a]]=k;
v[k]+=v[a]+v[b];v[a]=v[b]=0;
down(1),det(bk[a]),det(bk[b]),tot--;
}
}
}
int main()
{
ll i;read(n),read(m);
for (i=1;i<=n;i++)
{
read(a[++nn]);
if (!a[nn]) nn--;
}
v[++cnt]=a[1];
for (i=2;i<=nn;i++)
if ((a[i]>0&&a[i-1]>0)||(a[i]<0&&a[i-1]<0)) v[cnt]+=a[i];
else v[++cnt]=a[i];
for (i=1;i<=cnt;i++)
if (v[i]>0) ans+=v[i],tot++;
for (i=1;i<=cnt;i++) pre[i]=i-1,nxt[i]=i+1;
pre[1]=nxt[cnt]=-1;
Solve();
printf("%lld\n",ans);
return 0;
}