luogu 2048 超级钢琴 贪心+堆+RMQ

此题求长度在l,r,之间内的区间的前k大之和

1.静态区间第k大,不就是主席树么!

可是不会写啊,以后填坑吧

2.优先队列

固定左端点,选取以此为起点的长度l<=x<=r的区间,固定此范围后寻找此范围内最大所到位置t;

由于左端点已经固定且每次i相同的操作下只将一个点放入优先队列,故不会出现重复;

注意:rmq维护的是最大的前缀和所在位置,返回的也是位置

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define ll long long 
using namespace std;
const int N=500050;
const int Logn=20;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
namespace zjc{
    int n,k,L,R,a[N],sum[N],f[N][Logn],lg[N];ll ans;
    
    struct node{int op,l,r,t;
        friend bool operator <(node x,node y){
        return sum[x.t]-sum[x.op-1]<sum[y.t]-sum[y.op-1];}
    };priority_queue<node> q;
    
    void init(){
        lg[0]=-1;
        rep(i,1,n) f[i][0]=i,lg[i]=lg[i>>1]+1;
        rep(j,1,Logn)for(int i=1;i+(1<<j)-1<=n;i++)
        f[i][j]=sum[f[i][j-1]]>sum[f[i+(1<<j-1)][j-1]]?f[i][j-1]:f[i+(1<<j-1)][j-1];
    }
    int query(int x,int y){
        int s=lg[y-x+1];
        return sum[f[x][s]]>sum[f[y-(1<<s)+1][s]]?f[x][s]:f[y-(1<<s)+1][s];
    }
    void work(){
        n=read(),k=read(),L=read(),R=read();
        rep(i,1,n) a[i]=read(),sum[i]=sum[i-1]+a[i];
        init();
        for(int i=1;i+L-1<=n;i++){
            int l=i+L-1,r=min(i+R-1,n);
            int t=query(l,r);
            q.push((node){i,l,r,t});
        }
        for(int i=1;i<=k;i++){
            node u=q.top();q.pop();
            ans+=sum[u.t]-sum[u.op-1];
            if(u.l<=u.t-1) q.push((node){u.op,u.l,u.t-1,query(u.l,u.t-1)});
            if(u.t+1<=u.r) q.push((node){u.op,u.t+1,u.r,query(u.t+1,u.r)});
        }
        printf("%lld\n",ans);return;
    }
}
int main(){
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    zjc::work();
    return 0;
}  

 

posted @ 2018-09-13 10:10  ASDIC减除  阅读(101)  评论(0编辑  收藏  举报