luogu P2048 [NOI2010]超级钢琴

传送门

编号好评

先把所有数记个前缀和,然后对于某一个右端点(r(rgeq L)),能计入答案的(l)的范围为([max(r-R,0),r-L])

可以开一个大根堆,先对于所有右端点(r),加入(pre_r-min(pre_{l})),然后每次取出堆顶加入答案,弹掉堆顶,同时如果这是堆顶对应右端点减第(k)小的左端点的值,就把右端点减第(k+1)小的左端点的值加入堆中,这里我们可以使用主席树查询该区间内的任意第(k)小值

#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define eps (1e-7)

using namespace std;
const int N=500000+10;
const LL inf=1ll<<45;
il LL rd()
{
  re LL x=0,w=1;re char ch=0;
  while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
  while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
  return x*w;
}

#define mid ((l+r)>>1)

int s[N*20],ch[N*20][2],rt[N],tt;
int n,kk,L,R,a[N],b[N],pp[N][3];
il void inst(int p)
{
  rt[p]=++tt;
  int o1=rt[p],o2=rt[p-1],l=1,r=n;
  s[o1]=s[o2]+1;
  while(l<r)
    {
      if(a[p]<=mid)
        {
          ch[o1][0]=++tt,ch[o1][1]=ch[o2][1];
          o1=ch[o1][0],o2=ch[o2][0],r=mid;
        }
      else
        {
          ch[o1][0]=ch[o2][0],ch[o1][1]=++tt;
          o1=ch[o1][1],o2=ch[o2][1],l=mid+1;
        }
      s[o1]=s[o2]+1;
    }
}
int quer(int o1,int o2,int l,int r,int k)
{
  if(l==r) return b[l];
  int kkk=s[ch[o1][0]]-s[ch[o2][0]];
  if(k<=kkk) return quer(ch[o1][0],ch[o2][0],l,mid,k);
  else return quer(ch[o1][1],ch[o2][1],mid+1,r,k-kkk);
}
struct node
{
  LL x;
  int n;
  node(){x=-inf;}
}hp[N*3];
LL ans;
int tp;
il void ps(node a)
{
  hp[++tp]=a;
  int nw=tp;
  while(nw>1&&hp[nw].x>hp[nw>>1].x) swap(hp[nw],hp[nw>>1]),nw>>=1;
}
il void po()
{
  hp[1]=hp[tp],hp[tp--].x=-inf;
  int nw=1,p=2;
  while(hp[p].x>-inf)
    {
      if(hp[p+1].x>hp[p].x) ++p;
      if(hp[nw].x>hp[p].x) break;
      swap(hp[nw],hp[p]);
      nw=p,p<<=1;
    }
}
int q;

int main()
{
  n=rd()+1,kk=rd(),L=rd(),R=rd();
  for(int i=2;i<=n;i++) a[i]=b[i]=a[i-1]+rd();
  sort(b+1,b+n+1),unique(b+1,b+n+1);
  int nn=1;
  while(b[nn]<b[nn+1]) ++nn;
  for(int i=1;i<=n;i++)
    {
      a[i]=lower_bound(b+1,b+nn+1,a[i])-b;
      inst(i);
    }
  for(int i=L+1;i<=n;i++)
    {
      pp[i][0]=max(1,i-R),pp[i][1]=i-L,pp[i][2]=1;
      node xx;
      xx.x=(LL)(b[a[i]]-quer(rt[pp[i][1]],rt[pp[i][0]-1],1,n,pp[i][2])),xx.n=i;
      ps(xx);
    }
  for(int h=1;h<=kk;h++)
    {
      ans+=hp[1].x;
      int i=hp[1].n;
      po();
      ++pp[i][2];
      if(pp[i][2]>pp[i][1]-pp[i][0]+1) continue;
      node xx;
      xx.x=b[a[i]]-quer(rt[pp[i][1]],rt[pp[i][0]-1],1,n,pp[i][2]),xx.n=i;
      ps(xx);
    }
  printf("%lld
",ans);
  return 0;
}

原文地址:https://www.cnblogs.com/smyjr/p/9739244.html