NOI2010 超级钢琴
题目链接:戳我
RMQ版本
就是我们考虑记录一个三元组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;
}
主席树版本
也是维护一个三元组。
因为求的是一个连续的区间和,所以我们可以先做一下前缀和,然后固定右端点,在可选区间中选择最小的即可。
就是记录一下在这个pos为右端点的区间中,已经取到了第多少qwq
维护取第K大就是一个静态区间求第K的主席树经典应用qwq
然后放进堆里即可。每次取出最大的,然后放入以这个为右端点,的K+1大值。
记得要先离散化一下qwq,还有一直取到头(也就是前缀和减0)的情况——其实就是离散化的时候往数组里面放一个0即可。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#define MAXN 500010
using namespace std;
int n,k,L,R,top,tot;
int pre[MAXN],rt[MAXN],sum[MAXN];
long long ans;
struct T{int siz,val,ls,rs;}t[MAXN<<5];
struct Node
{
int pos,v,cnt;
friend bool operator < (struct Node x,struct Node y)
{return x.v<y.v;}
};
priority_queue<Node>q;
inline void modify(int &x,int f,int l,int r,int k)
{
x=++tot;
t[x]=t[f],t[x].siz++;
if(l==r) return;
int mid=(l+r)>>1;
if(k<=mid) modify(t[x].ls,t[f].ls,l,mid,k);
else modify(t[x].rs,t[f].rs,mid+1,r,k);
}
inline int query(int x,int f,int l,int r,int k)
{
if(l==r) return l;
int cur=t[t[x].ls].siz-t[t[f].ls].siz;
int mid=(l+r)>>1;
if(k<=cur) return query(t[x].ls,t[f].ls,l,mid,k);
else return query(t[x].rs,t[f].rs,mid+1,r,k-cur);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d%d%d",&n,&k,&L,&R);
n++;
for(int i=2;i<=n;i++)
scanf("%d",&sum[i]),sum[i]=sum[i-1]+sum[i],pre[++top]=sum[i];
pre[++top]=0;
sort(&pre[1],&pre[top+1]);
top=unique(&pre[1],&pre[top+1])-pre-1;
for(int i=1;i<=n;i++) sum[i]=lower_bound(&pre[1],&pre[top+1],sum[i])-pre;
for(int i=1;i<=n;i++) modify(rt[i],rt[i-1],1,top,sum[i]);
for(int i=L+1;i<=n;i++)
{
int pos=query(rt[max(0,i-L)],rt[max(0,i-R-1)],1,top,1);
q.push((Node){i,pre[sum[i]]-pre[pos],1});
}
while(k--)
{
Node now=q.top();q.pop();
now.cnt++;
ans+=now.v;
// printf("ans=%lld\n",ans);
if(now.cnt>min(max(0,now.pos-L),R-L+1)) continue;
int cur=query(rt[max(0,now.pos-L)],rt[max(0,now.pos-R-1)],1,top,now.cnt);
now.v=pre[sum[now.pos]]-pre[cur];
q.push(now);
}
printf("%lld\n",ans);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!