您的位置:首页 > 其它

2006: [NOI2010]超级钢琴 ST表+优先队列

2016-04-11 08:22 369 查看
来补几发题解吧…从HN集训回来也做了几道题一直没发题解。

我们首先求出前缀和,然后枚举左端点l,右端点的所在范围就是[l+L−1,l+R−1],然后我们要求出这段区间内的最大值,然后加入堆里。每次取出堆顶元素,假设为区间[l..x],然后再把区间[l+L−1,x−1],[x+1,l+R−1]的最大值分别加入堆里。然后重复m此获得答案。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#define N 500005
using namespace std;
struct data
{
int i,l,r,t;
};
int n,K,L,R;
long long ans;
int a
,f
[20];
inline bool operator<(data x,data y)
{
return a[x.t]-a[x.i-1]<a[y.t]-a[y.i-1];
}
inline int query(int l,int r)
{
int k=log2(r-l+1);
int t1=f[l][k],t2=f[r-(1<<k)+1][k];
if (a[t1]>a[t2]) return t1;
else return t2;
}
inline void solve()
{
priority_queue<data> q;
for (int i=1;i<=n-L+1;i++)
{
int j=min(n,i+R-1);
q.push((data){i,i+L-1,j,query(i+L-1,j)});
}
for (int i=1;i<=K;i++)
{
data now=q.top(); q.pop();
ans+=a[now.t]-a[now.i-1];
if (now.t-1>=now.l) q.push((data){now.i,now.l,now.t-1,query(now.l,now.t-1)});
if (now.t+1<=now.r) q.push((data){now.i,now.t+1,now.r,query(now.t+1,now.r)});
}
}
int main()
{
scanf("%d%d%d%d",&n,&K,&L,&R);
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
a[i]=a[i-1]+x;
}
for (int i=1;i<=n;i++)
f[i][0]=i;
for (int j=1;j<=18;j++)
for (int i=1;i<=n;i++)
if (i+(1<<j)-1<=n)
{
int t1=f[i][j-1],t2=f[i+(1<<(j-1))][j-1];
if (a[t1]<a[t2]) f[i][j]=t2;
else f[i][j]=t1;
}
solve();
cout << ans << endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: