Problem
Description
Input
Output
Sample Input
样例输入1:
3 4
1 3 4
样例输入2:
3 3
10 2 7
Sample Output
样例输出1:
8 7 4 4
样例输出2:
19 12 10
Data Constraint
Hint
Solution
我们可以发现,如果这一次输出区间[l,r]的和,那么上一个输出的数要么是区间[l−1,r]的和,要么是区间[l,r+1]的和。
那么我们先维护一个堆,堆顶为区间[1,n]的和。设当前堆顶为[l1,r1],那么下一个答案可能是[l1+1,r1]或[l1,r1−1]。那么我们将[l1+1,r1]和[l1,r1−1]加进堆,维护一下堆就行了。
问题来了,[l1,r1]可能由[l1−1,r1]过来,也有可能从[l1,r1+1]过来,重复了。
于是我们只用考虑当r1=n时才将[l1+1,r1]加入堆。因为这样固定了一个端点,那么所有的[l1,r1−1]只会加入堆一次,避免了重复。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define N 100010
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
LL d[N*10][3],sum,a[N];
LL i,j,k,l,r,n,t,tot;
void up(LL x)
{
LL p=x;
while (p>1 && d[p/2][0]<d[p][0])
{
swap(d[p],d[p/2]);
p/=2;
}
}
void down(LL x)
{
LL l=x*2,r=x*2+1;
while (l<=tot && d[x][0]<=d[l][0] || (r<=tot) && d[x][0]<=d[r][0])
{
LL mx=l;
if (r<=tot && d[r][0]>d[l][0]) mx=r;
swap(d[x],d[mx]);
x=mx;
l=x*2,r=x*2+1;
}
}
void ins(LL x,LL l,LL r)
{
d[++tot][0]=x;
d[tot][1]=l;
d[tot][2]=r;
up(tot);
}
void del(LL x)
{
if (d[tot][0]<d[x][0])
{
memcpy(d[x],d[tot],sizeof(d[x]));tot--;
down(x);
} else
{
memcpy(d[x],d[tot],sizeof(d[x]));tot--;
up(x);
}
}
int main()
{
scanf("%lld%lld",&n,&k);
fo(i,1,n)
{
scanf("%lld",&a[i]);
sum+=a[i];
}
ins(sum,1,n);
fo(i,1,k)
{
sum=d[1][0];
printf("%lld ",sum);
l=d[1][1],r=d[1][2];
if (l+1<=r && r==n) ins(sum-a[l],l+1,r);
if (l<=r-1) ins(sum-a[r],l,r-1);
del(1);
}
}