BZOJ2006: [NOI2010]超级钢琴

题解 :很显然的 我们直接无法处理前K大的和 但是我们可以采取分裂的方式 维护以一个端点为定点 左边表示这一段的和 很容易的我们想到主席树 永久化标记来维护每个点到右端的区间和 然后用堆维护一个五元组 表示的 是当前定点为pos时 在[l,r]范围内到定点的最大和的值是多少 以及这个位置 然后我们就可以用堆维护答案了

#include <bits/stdc++.h>
#define ll long long
const int MAXN=5e5+10;
const int inf=1e9;
using namespace std;
int a[MAXN];
typedef struct node{
    int l,r,maxx,pos,flag;
}node;
node d[41*MAXN];int cnt;int rt[MAXN];
void up(int x,int l,int r){
    if(d[x].l)d[x].maxx=d[d[x].l].maxx,d[x].pos=d[d[x].l].pos;
    else d[x].pos=l,d[x].maxx=0;
    if(d[x].r){
        if(d[d[x].r].maxx>d[x].maxx)d[x].maxx=d[d[x].r].maxx,d[x].pos=d[d[x].r].pos;
    }
    else{
        if(d[x].maxx<0)d[x].maxx=0,d[x].pos=r;
    }
}
void update(int &x,int y,int l,int r,int ql,int qr,int vul){
    x=++cnt;d[x]=d[y];
    if(l==r)d[x].pos=l;
    if(ql<=l&&r<=qr){d[x].maxx+=vul;d[x].flag+=vul;return ;}
    int mid=(l+r)>>1;
    if(ql<=mid)update(d[x].l,d[y].l,l,mid,ql,qr,vul);
    if(qr>mid)update(d[x].r,d[y].r,mid+1,r,ql,qr,vul);
    //cout<<d[x].pos<<endl;
    up(x,l,r);
    //cout<<l<<" "<<r<<" "<<d[x].pos<<" "<<d[x].maxx<<" "<<vul<<" "<<ql<<" "<<qr<<endl;
}
int maxx,pos1;
void querty(int x,int l,int r,int ql,int qr,int key){
    if(!x){if(maxx<key)maxx=key,pos1=max(ql,l);return ;}
    if(ql<=l&&r<=qr){
        if(maxx<d[x].maxx+key)maxx=d[x].maxx+key,pos1=d[x].pos;
        return ;
    }
    int mid=(l+r)>>1;
    if(ql<=mid)querty(d[x].l,l,mid,ql,qr,key+d[x].flag);
    if(qr>mid)querty(d[x].r,mid+1,r,ql,qr,key+d[x].flag);
}
typedef struct Node{
    int pos,l,r,vul,mid;
    friend bool operator<(Node aa,Node bb){return aa.vul<bb.vul;}
}Node;
priority_queue<Node>que;
int main(){
    int n,k,l,r;scanf("%d%d%d%d",&n,&k,&l,&r);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)update(rt[i],rt[i-1],1,n,1,i,a[i]);
    for(int i=l;i<=n;i++){
        int t1=max(1,i-r+1);
        maxx=-1*inf;querty(rt[i],1,n,t1,i-l+1,0);
        que.push((Node){i,t1,i-l+1,maxx,pos1});
        //cout<<i<<" "<<pos1<<" "<<maxx<<endl;
    }
    ll ans=0;
    for(int i=1;i<=k;i++){
        Node t=que.top();que.pop();
        ans+=t.vul;
        if(t.l<t.mid)maxx=-1*inf,querty(rt[t.pos],1,n,t.l,t.mid-1,0),que.push((Node){t.pos,t.l,t.mid-1,maxx,pos1});
        if(t.r>t.mid)maxx=-1*inf,querty(rt[t.pos],1,n,t.mid+1,t.r,0),que.push((Node){t.pos,t.mid+1,t.r,maxx,pos1});     
    }
    printf("%lld\n",ans);
    return 0;
}

 

2006: [NOI2010]超级钢琴

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 3957  Solved: 1997
[Submit][Status][Discuss]

Description

小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的
音乐。 这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。 一个“超级
和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的
所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。 
小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。
我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最
大值是多少。

Input

第一行包含四个正整数n, k, L, R。其中n为音符的个数,k为乐曲所包含的超级和弦个数,L和R分别是超级和弦所
包含音符个数的下限和上限。 接下来n行,每行包含一个整数Ai,表示按编号从小到大每个音符的美妙度。
N<=500,000
k<=500,000
-1000<=Ai<=1000,1<=L<=R<=N且保证一定存在满足条件的乐曲

Output

只有一个整数,表示乐曲美妙度的最大值。

Sample Input

4 3 2 3
3
2
-6
8

Sample Output

11

【样例说明】
共有5种不同的超级和弦:
音符1 ~ 2,美妙度为3 + 2 = 5
音符2 ~ 3,美妙度为2 + (-6) = -4
音符3 ~ 4,美妙度为(-6) + 8 = 2
音符1 ~ 3,美妙度为3 + 2 + (-6) = -1
音符2 ~ 4,美妙度为2 + (-6) + 8 = 4
最优方案为:乐曲由和弦1,和弦3,和弦5组成,美妙度为5 + 2 + 4 = 11。
posted @ 2018-08-07 23:52  wang9897  阅读(158)  评论(0编辑  收藏  举报