【题解】洛谷P2048 [NOI2010]超级钢琴

前往:我自己搭建的博客

题目

洛谷P2048[NOI2010]超级钢琴

题解

题目简化后即求前k大的子区间。先求前缀和s[],枚举子区间的左端点l,再找最优的右端点r(即枚举s[l-1],再找符合条件的最大的s[r]),找最大的s[r]的过程即求静态区间最大值的过程,采用ST表。将上一步找出的子区间放入优先队列中维护,接下来每次取出一个区间和最大的元素,计入答案,并求与其左端点相同,s[r]第二大的区间。求次大的s[r]时,只需先找出最大的s[r]的位置,然后在它的左侧和右侧分别用ST表求s[r]的最大值,然后都作为候选答案加入到优先队列中。

代码

#include 
using namespace std;
const int maxn=5e5+5;
typedef long long ll;
int n,k,L,R;
int s[maxn],f[maxn][20],lg2[maxn];
struct music{int l,rmin,rmax,max_p,sum;};
//一个music表示一个和弦,即一个子区间
//l表示区间左端点-1,max_p表示从范围[rmin,rmax]中求出的最大的s[r]的下标,sum表示区间和 
priority_queue q;
bool operator <(const music &x,const music &y) {return x.sum'9')) ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s*f;
}
inline void get_ST() //维护最值,改成维护最值的下标 
{
	for(int i=1;i<=n;i++) f[i][0]=i;
	for(int i=2;i<=n;i++) lg2[i]=lg2[i>>1]+1;
	for(int j=1;(1<s[f[i+(1<<(j-1))][j-1]] ? f[i][j-1] : f[i+(1<<(j-1))][j-1];
}
inline int RMQ(int l,int r)
{
	int t=lg2[r-l+1];
	return s[f[l][t]]>s[f[r-(1<=x.max_p+1) q.push((music){x.l,x.max_p+1,x.rmax,RMQ(x.max_p+1,x.rmax),s[RMQ(x.max_p+1,x.rmax)]-s[x.l]});
	}	//注意判断合法性 
	printf("%lld\n",ans);
}
	
int main()
{
	n=read(),k=read(),L=read(),R=read();
	for(int i=1;i<=n;i++) s[i]=s[i-1]+read();
	get_ST(); solve();
	
	return 0;
}

你可能感兴趣的:(【题解】洛谷P2048 [NOI2010]超级钢琴)