P2048 [NOI2010]超级钢琴 主席树+优先队列

首先用前缀和 o1 地维护区间和

对于每个序列尾 将将满足长度的序列的最大值放入优先队列里  然后每次弹出一个 将 该尾部的序列的这个的前驱放入优先队列   重复k次即可  

用主席树来维护即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
const int N=1e6+100;
int T[N<<5],lson[N<<5],rson[N<<5],ncnt,t[N<<5];

void upnode(int x,int l,int r,int pre,int &pos)
{
    pos=++ncnt;
    t[pos]=t[pre]+1;lson[pos]=lson[pre];rson[pos]=rson[pre];
    if(l==r)return ;int m=(l+r)>>1;
    if(x<=m)upnode(x,l,m,lson[pre],lson[pos]);
    else upnode(x,m+1,r,rson[pre],rson[pos]);
}
int qk(int k,int l,int r,int pre,int pos)
{
    int x=t[lson[pos]]-t[lson[pre]];
    if(l==r)return l;int m=(l+r)>>1;
    if(k<=x)return qk(k,l,m,lson[pre],lson[pos]);
    else return qk(k-x,m+1,r,rson[pre],rson[pos]);
}
struct node
{
    int v,k,pos;
    bool operator<(const node &b)const 
    {
        return v<b.v;
    }
};
priority_queue<node>q;
int a[N],L,R,k,n,s[N];
int main()
{   
    scanf("%d%d%d%d",&n,&k,&L,&R);
    n++;//空出一位0  方便前缀和
    rep(i,2,n)
    {
        scanf("%d",&a[i]);
        a[i]+=a[i-1];s[i]=a[i];
    }
    sort(s+1,s+1+n);
    int nn=unique(s+1,s+1+n)-s-1;
    rep(i,1,n)a[i]=lower_bound(s+1,s+1+nn,a[i])-s;

    rep(i,1,n)upnode(a[i],1,nn,T[i-1],T[i]);

    rep(i,L+1,n)
    {
        node x;x.k=1;x.pos=i;
        x.v=s[a[i]]-s[qk(1,1,nn,T[max(0,i-R-1)],T[i-L] )];
        q.push(x);
    }
    ll ans=0;
    while(k--)
    {
        node u=q.top();q.pop();
        ans+=u.v;
        if(u.k==min(R-L+1,u.pos-L))continue;
        u.k++;
        u.v=s[a[u.pos]]-s[qk(u.k,1,nn,T[max(0,u.pos-R-1)],T[max(0,u.pos-L)])];
        q.push(u);
    }
    cout<<ans;
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/bxd123/p/11508551.html