洛谷 P2048 [NOI2010] 超级钢琴
求其前缀和,对于每一个i,可选值的范围是[i+L-1,i+R-1],假设选了pos,那么得到的贡献就是a[pos]-a[i-1],也就是说需要选择前m大的值相加;
如果对于一个i,我在它可选值范围内选了pos,得到贡献后,对于i的下一个最大值可能在[i-L+1,pos-1]内,或者[pos+1,i+R-1]内;
用优先队列维护元组{i,i的可选值范围,该范围内最大值的位置pos},按a[pos] - a[i-1]的值从大到小;
考虑用线段树维护区间最大值和最大值所在位置;
一开始就将每一个i的元组存入优先队列,于是每次都从堆顶拿一个元组处理并加上贡献即可;
#include <bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs rt<<1|1
#define LL long long
#define PI acos(-1.0)
#define eps 1e-8
#define Pair pair<double,double>
// notice
#define mod 998244353
#define MAXN 2e6
#define MS 500009
LL n,m;
LL cl,cr;
LL a[MS];
struct node{
LL pos,val;
}p[MS<<2];
struct nod{
LL o,l,r,pos,val;
};
priority_queue<nod > Q;
bool operator < (nod t1,nod t2){
return t1.val-a[t1.o-1] < t2.val-a[t2.o-1];
}
void push_up(int rt){
p[rt].val = max(p[ls].val,p[rs].val);
if(p[ls].val >= p[rs].val)
p[rt].pos = p[ls].pos;
else
p[rt].pos = p[rs].pos;
}
void build(int l,int r,int rt){
if(l == r){
p[rt] = {l,a[l]};
return;
}
int m = l+r>>1;
build(l,m,ls);
build(m+1,r,rs);
push_up(rt);
}
node query(int L,int R,int l,int r,int rt){
if(L <= l && r <= R){
return p[rt];
}
int m = l+r>>1;
if(m < L) return query(L,R,m+1,r,rs);
else if(m >= R) return query(L,R,l,m,ls);
else{
node ans;
node t1 = query(L,R,l,m,ls);
node t2 = query(L,R,m+1,r,rs);
ans.val = max(t1.val,t2.val);
if(t1.val >= t2.val)
ans.pos = t1.pos;
else
ans.pos = t2.pos;
return ans;
}
}
int main() {
ios::sync_with_stdio(false);
cin >> n >> m >> cl >> cr;
for(int i=1;i<=n;i++){
cin >> a[i];
a[i] += a[i-1];
}
build(1,n,1);
for(int i=1;i+cl-1<=n;i++){
LL tl = i+cl-1;
LL tr = min(i+cr-1,n);
node t = query(tl,tr,1,n,1);
Q.push({i,tl,tr,t.pos,t.val});
}
LL ans = 0;
while(m--){
nod cc = Q.top();
Q.pop();
ans += cc.val - a[cc.o-1];
if(cc.l <= cc.pos-1){
node ql = query(cc.l,cc.pos-1,1,n,1);
Q.push({cc.o,cc.l,cc.pos-1,ql.pos,ql.val});
}
if(cc.pos+1 <= cc.r){
node qr = query(cc.pos+1,cc.r,1,n,1);
Q.push({cc.o,cc.pos+1,cc.r,qr.pos,qr.val});
}
}
cout << ans << "\n";
return 0;
}