洛谷 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;
}

posted @ 2021-06-03 18:12  棉被sunlie  阅读(67)  评论(0)    收藏  举报