【BZOJ】2006: [NOI2010]超级钢琴(前缀和+RMQ+堆)

题目

传送门:QWQ

 

 

分析

又不会做。。。。。。。

显然很好想到前缀和处理一下。

然后考虑最大化结果,直接上st表。

问题来了,然后呢?

怎么做$ length \in [l,r]  $ 呢? 

是设一个五元组 (i,l,r,val,pos) 。

i是左端点,l,r是右端点范围,val是 i 到 pos的和, pos是 右端点位置。

 然后对于  l,r   二分,扔进优先队列处理 。取出前 k 大,累加一下就是答案。

完了。

 

 

 

代码

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=500005;
int n,posi[maxn][23];
int sum[maxn],Log2[maxn];
struct Node{
    int i,l,r,val,pos;
    bool operator < (const Node& a) const{ return val<a.val;}
};

inline int Max(int x,int y) {return sum[x]>sum[y]? x:y;}
void ST(){
    Log2[0]=-1;
    for(int i=1;i<=n;i++)
        if((i&(i-1))==0) Log2[i]=Log2[i-1]+1; else Log2[i]=Log2[i-1];
    for(int i=1;i<=n;i++) posi[i][0]=i;

    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)<=n+1;i++){
            posi[i][j]=Max(posi[i][j-1],posi[i+(1<<(j-1))][j-1]);
        }
}
inline int RMQ(int l,int r){
    int tmp=Log2[r-l+1];
    return Max(posi[l][tmp],posi[r-(1<<tmp)+1][tmp]);
}
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
priority_queue<Node> que;
int main()
{
    int k,L,R;
    scanf("%d%d%d%d",&n,&k,&L,&R);
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+read();
    }
    ST();
    for(int i=1;i<=n+1-L;i++){
        int pos=RMQ(i+L-1,min(n,i+R-1));
//        printf("---------- %d %d %d\n",i+L-1,min(n,i+R-1),pos);
        que.push((Node){i,i+L-1,min(n,i+R-1),sum[pos]-sum[i-1],pos});
    }
    ll ans=0;
    while(k){
        Node x=que.top();que.pop();
//        printf("##########  %d %d %d\n",x.i,x.pos,x.val);
        k--; ans+=(ll)x.val;
        Node ls=x,rs=x;
        ls.r=x.pos-1; rs.l=x.pos+1;
        if(ls.r>=ls.l) {
            ls.pos=RMQ(ls.l,ls.r); ls.val=sum[ls.pos]-sum[ls.i-1]; que.push(ls);
        }
        if(rs.r>=rs.l) {
            rs.pos=RMQ(rs.l,rs.r); rs.val=sum[rs.pos]-sum[rs.i-1]; que.push(rs);
        }
    }
//    puts("-----------debug------------");
//    for(int i=1;i<=n;i++)    printf("%d ",Log2[i]);
    printf("%lld\n",ans);
    return 0;
}

 

 

posted @ 2018-06-06 21:50  noble_(noblex)  阅读(145)  评论(0编辑  收藏  举报
/* */