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; }