标签:rmq 子序列和 soft content 决定 需要 name 注意 而不是
题目描述
输入
输出
只有一个整数,表示乐曲美妙度的最大值。
样例输入
4 3 2 3
3
2
-6
8
样例输出
11
题解
倍增RMQ(貌似这个叫做ST表)+STL-堆
首先我们将连续子序列和转化为前缀和相减,那么对于每个左端点,找它的右端点,就转变为求某范围内前缀和的最大值、次大值、...
但是直接拿出整个序列显然会TLE+MLE。
我们考虑,如果左端点t,右端点[l,r],我们找出属于[l,r]的位置p,使得sum[p]最大。那么很显然,当且仅当p被选择之后,[l,p-1]和[p+1,r]内的右端点才可能会被选择。
所以我们可以维护一个结构体,储存t、l、r、p、v,分别表示左端点、右端点区间的左位置、右端点区间的右位置、右端点区间最大值的位置、右端点区间最大值,显然v=sum[p]-sum[t-1]。我们优先选择v较大的区间把它拿出来,把它的v加入到答案中。然后考虑剩下的[l,p-1]和[p+1,r],如果存在这些区间的话,采取相同的方式处理即可。这个过程显然可以使用堆来维护。
维护区间最大值即位置。可以使用倍增RMQ来解决,时间复杂度更低一些。
因此总的时间复杂度为$O((n+k)\log n)$
另外需要注意的是priority_queue需要重载<运算符,而不是>(尽管它是大根堆)
#include <cstdio> #include <queue> #define N 500010 using namespace std; struct data { int t , b , e , v , p; data() {} data(int t0 , int b0 , int e0 , int v0 , int p0) {t = t0 , b = b0 , e = e0 , v = v0 , p = p0;} bool operator<(const data a)const {return v < a.v;} }tmp; priority_queue<data> q; int sum[N] , maxn[N][20] , maxp[N][20] , log[N]; int getmaxn(int x , int y) { int k = log[y - x + 1]; return max(maxn[x][k] , maxn[y - (1 << k) + 1][k]); } int getmaxp(int x , int y) { int k = log[y - x + 1]; return maxn[x][k] > maxn[y - (1 << k) + 1][k] ? maxp[x][k] : maxp[y - (1 << k) + 1][k]; } int main() { int n , k , l , r , i , j , x , y; long long ans = 0; scanf("%d%d%d%d" , &n , &k , &l , &r); for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &x) , sum[i] = sum[i - 1] + x , maxn[i][0] = sum[i] , maxp[i][0] = i; for(i = 2 ; i <= n ; i ++ ) log[i] = log[i >> 1] + 1; for(i = 1 ; i <= log[n] ; i ++ ) { for(j = 1 ; j <= n - (1 << i) + 1 ; j ++ ) { if(maxn[j][i - 1] > maxn[j + (1 << (i - 1))][i - 1]) maxn[j][i] = maxn[j][i - 1] , maxp[j][i] = maxp[j][i - 1]; else maxn[j][i] = maxn[j + (1 << (i - 1))][i - 1] , maxp[j][i] = maxp[j + (1 << (i - 1))][i - 1]; } } for(i = 1 ; i <= n - l + 1 ; i ++ ) x = i + l - 1 , y = min(i + r - 1 , n) , q.push(data(i , x , y , getmaxn(x , y) - sum[i - 1] , getmaxp(x , y))); while(k -- ) { tmp = q.top() , q.pop() , ans += tmp.v; if(tmp.p > tmp.b) x = tmp.b , y = tmp.p - 1 , q.push(data(tmp.t , x , y , getmaxn(x , y) - sum[tmp.t - 1] , getmaxp(x , y))); if(tmp.p < tmp.e) x = tmp.p + 1 , y = tmp.e , q.push(data(tmp.t , x , y , getmaxn(x , y) - sum[tmp.t - 1] , getmaxp(x , y))); } printf("%lld\n" , ans); return 0; }
【bzoj2006】[NOI2010]超级钢琴 倍增RMQ+STL-堆
标签:rmq 子序列和 soft content 决定 需要 name 注意 而不是
原文地址:http://www.cnblogs.com/GXZlegend/p/7072556.html