BZOJ2006 ST表 + 堆

https://www.lydsy.com/JudgeOnline/problem.php?id=2006

题意:在长度N的序列中求K段长度在L到R之间的区间,使得他们的和最大

很容易想到要求一个前缀和。

然后每一个位置i就对应后面的一段i + L - 1 ~ i + R - 1的区间,如果考虑暴力的话,就把每一个值对应的区间内所有的值再全部加入优先队列,取出K个。

看了下数据范围发现不可行。

考虑ST表求最值,在每一个对应区间内找一个最大值,仔细一想也觉得不可行,因为一个区间内的次大值很有可能是会对答案产生贡献的。

事实上我们对ST表加入一点小操作,使得他维护的是静态区间内的最大值下标,rmq(l,r)返回的是l到r区间内最大值的下标p,我们首先将N个三元组i,l,r加入堆,他的贡献是pre[rmq(l,r)] - pre[i - 1],将贡献从大到小排序,当我们处理完一个三元组的时候,再加入分裂开的三元组i,l,p - 1与i,p + 1,r,也就是说,当区间内最大值计算完之后,就往堆中放入一个次大值和次次大值,以此类推即可。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
const double eps = 1e-9;
const int maxn = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,L,R;
int a[maxn];
LL pre[maxn];
const int SP = 20;
int Max[maxn][SP];
int mm[maxn];
void initRMQ(int n,LL b[]){
    mm[0] = -1;
    for(int i = 1; i <= n; i ++){
        mm[i] = ((i & (i - 1)) == 0)?mm[i - 1] + 1:mm[i - 1];
        Max[i][0] = i;
    }
    for(int j = 1; j <= mm[n]; j ++){
        for(int i = 1; i + (1 << j) - 1 <= n ; i ++){
            int x = Max[i][j - 1],y = Max[i + (1 << (j - 1))][j - 1];
            Max[i][j] = b[x] > b[y]?x:y;
        }
    }
}
int rmq(int x,int y,LL b[]){
    int k = mm[y - x + 1];
    return b[Max[x][k]] > b[Max[y - (1 << k) + 1][k]]?Max[x][k]:Max[y - (1 << k) + 1][k];
}
struct node{
    int l,r,o;
    node(){}
    node(int l,int r,int o):l(l),r(r),o(o){}
    LL ans(){
        return pre[rmq(l,r,pre)] - pre[o - 1];
    }
    friend bool operator < (node a,node b){
        return a.ans() < b.ans();
    }
};
int main(){
    N = read(); M = read(); L = read(); R = read();
    for(int i = 1; i <= N ; i ++){
         a[i] = read();
         pre[i] = pre[i - 1] + a[i];
    }
    initRMQ(N,pre);
    priority_queue<node>Q;
    for(int i = 1; i <= N ; i ++){
        if(i + L - 1 > N) break;
        Q.push(node(i + L - 1,min(i + R - 1,N),i));
    }
    LL ans = 0;
    while(M--){
        node u = Q.top(); Q.pop();
        ans += u.ans();
        int p = rmq(u.l,u.r,pre);
        if(p != u.l) Q.push(node(u.l,p - 1,u.o));
        if(p != u.r) Q.push(node(p + 1,u.r,u.o));
    }
    Prl(ans);
    return 0;
}

 

posted @ 2019-02-12 11:41  Hugh_Locke  阅读(192)  评论(0编辑  收藏  举报