【题解】
(划分树做法)
要求出长度为l~r的前k大连续和,可以转化为k次求第i大连续和,这与划分树的作用有关时间复杂度:划分树预处理_O( n*log(n) ) +Ⅰ_O( n*log(n) ) +Ⅱ_O( k*log(n) )
【代码】
#include
#include
typedef long long LL;
struct node
{
int v[500005],num[500005];
};
node T[20];
int s[500005]={0},p[500005]={0},heap[500005]={0},pos[500005]={0};
int ph=0;
int min(int a,int b)
{
if(amid) j--;
if(i<=j)
{
jh(&s[i],&s[j]);
i++;
j--;
}
}
if(j>low) kp(low,j);
if(is[mid]) T[deep+1].v[rn++]=T[deep].v[i];
if(T[deep].v[i]==s[mid])
{
same++;
if(isame>=same)
{
T[deep+1].v[ln++]=T[deep].v[i];
T[deep].num[i]++;
}
else T[deep+1].v[rn++]=T[deep].v[i];
}
}
build(left,mid,deep+1);
build(mid+1,right,deep+1);
}
int cx(int x,int y,int k,int left,int right,int deep)
{
int mid=(left+right)/2,before,have,b,h,tx,ty,fk=y-x+1+1-k;
if(left==right) return T[deep].v[left];
if(x==left)
{
before=0;
have=T[deep].num[y];
}
else
{
before=T[deep].num[x-1];
have=T[deep].num[y]-T[deep].num[x-1];
}
if(fk<=have)//左
{
tx=left+before;
ty=left+before+have-1;
k=ty-tx+1+1-fk;
return cx(tx,ty,k,left,mid,deep+1);
}
else//右
{
b=x-1-left-before+1;
h=y-x+1-have;
tx=mid+1+b;
ty=mid+1+b+h-1;
k=ty-tx+1+1-(fk-have);
return cx(tx,ty,k,mid+1,right,deep+1);
}
}
void tj(int x,int t)
{
int i;
heap[++ph]=t;
pos[ph]=x;
for(i=ph;i!=1;i/=2)
{
if(heap[i]>heap[i/2]) jh_heap(i,i/2);
else return;
}
}
void sc()
{
int i=1;
jh_heap(1,ph);
ph--;
while(i*2<=ph)
{
i*=2;
if(i+1<=ph&&heap[i+1]>heap[i]) i++;
if(heap[i]>heap[i/2]) jh_heap(i,i/2);
else return;
}
}
int main()
{
LL ans=0;
int n,k,l,r,i,x;
scanf("%d%d%d%d",&n,&k,&l,&r);
for(i=1;i<=n;i++)
{
scanf("%d",&s[i]);
s[i]+=s[i-1];
T[0].v[i]=s[i];
}
T[0].v[0]=0;
kp(1,n);
build(1,n,0);
for(i=1;i<=n-l+1;i++)
{
p[i]=1;
tj(i,cx(i+l-1,min(n,i+r-1),1,1,n,0)-T[0].v[i-1]);
}
for(i=1;i<=k;i++)
{
ans+=(LL)heap[1];
x=pos[1];
sc();
p[x]++;
if((x+l-1)+p[x]-1<=min(n,x+r-1)) tj(x,cx(x+l-1,min(n,x+r-1),p[x],1,n,0)-T[0].v[x-1]);
}
printf("%lld",ans);
return 0;
}