NOI2010 超级钢琴

题目链接:戳我

就是我们考虑记录一个三元组qwq,一个是pos,一个是l,一个是r。
我们可以用ST表来查询固定左端点,右端点在一段区间内的最大值所在的位置。

然后我们使用优先队列,不断累加最大值,然后弹出,求它的区间的子区间内的最大值。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define MAXN 500010
using namespace std;
int n,l,r,k,cnt;
long long ans;
int log2[MAXN],st[MAXN][21],sum[MAXN],a[MAXN];
struct Node{
    int st,l,r,maxpos;
    friend bool operator < (struct Node x,struct Node y)
        {return (sum[x.maxpos]-sum[x.st-1])<(sum[y.maxpos]-sum[y.st-1]);}
};
priority_queue<Node>q;
inline void init()
{
    for(int i=1;i<=20;i++)
    {
        for(int j=1;j+(1<<i)-1<=n;j++)
        {
            int cur1=st[j][i-1];
            int cur2=st[j+(1<<(i-1))][i-1];
            if(sum[cur1]>sum[cur2]) st[j][i]=cur1;
            else st[j][i]=cur2;
        }
    }
}
inline int query(int l,int r)
{
    if(l==r) return l;
    int cur1=st[l][log2[r-l+1]];
    int cur2=st[r-(1<<log2[r-l+1])+1][log2[r-l+1]];
    if(sum[cur1]>sum[cur2]) return cur1;
    else return cur2;
}
inline void solve()
{
    for(int i=1;i<=n;i++)
    {
        int ll=i+l-1,rr=min(n,i+r-1);
        if(ll>n) continue;
        q.push((Node){i,ll,rr,query(ll,rr)});
        // printf("%d %d %d %d\n",i,ll,rr,q.top().maxpos);
    }
    while(!q.empty()&&cnt<k)
    {
        Node u=q.top(); q.pop();
        // printf("maxpos=%d\n",u.maxpos);
        ans+=sum[u.maxpos]-sum[u.st-1];
        cnt++;
        if(u.maxpos-1>=u.l) q.push((Node){u.st,u.l,u.maxpos-1,query(u.l,u.maxpos-1)});
        if(u.maxpos+1<=u.r) q.push((Node){u.st,u.maxpos+1,u.r,query(u.maxpos+1,u.r)});
    }
    printf("%lld\n",ans);
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    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++) st[i][0]=i;
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
    // for(int i=1;i<=n;i++) printf("sum[%d]=%d\n",i,sum[i]);
    log2[0]=-1;
    for(int i=1;i<=n;i++) log2[i]=log2[i>>1]+1;
    // for(int i=1;i<=n;i++) printf("log2[%d]=%d\n",i,log2[i]);
    init();
    solve();
    return 0;
}
上一篇:复杂链表的复制


下一篇:identityserver4之refresh token