bzoj2006 [NOI2010]超级钢琴
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2006
【题解】
思路巧妙啊!
前置技能:序列和可以转化成前缀和的形式,那么前缀和左端点固定了右端点就是区间找最大值了。
记录五元组(from, l, r, pos, val)表示从from开始,右端点在[l,r]之间,在pos处取max,取max的值是val。
那么按照val扔到堆里,每次取出最大的,从pos分裂成两半,要兹磁求最大值,所以st表就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# include <queue> # include <stdio.h> # include <string.h> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; const int mod = 1e9+7; # define RG register struct pa { int x, l, r, mx, v; pa() {} pa(int x, int l, int r, int mx, int v) : x(x), l(l), r(r), mx(mx), v(v) {} friend bool operator < (pa a, pa b) { return a.v<b.v; } }; int n, k, L, R; int a[M], s[M]; namespace ST { struct rmq { int i, v; rmq() {} rmq(int i, int v) : i(i), v(v) {} friend bool operator <(rmq a, rmq b) { return a.v<b.v; } friend bool operator >(rmq a, rmq b) { return a.v>b.v; } }; int n, Log2[M]; rmq f[M][20]; inline void init(int _n) { n = _n; Log2[1] = 0; for (int i=2; i<=n; ++i) Log2[i] = Log2[i>>1] + 1; for (int i=1; i<=n; ++i) f[i][0] = rmq(i, s[i]); for (int j=1; j<=19; ++j) for (int i=1; i+(1<<j)-1<=n; ++i) f[i][j] = max(f[i][j-1], f[i+(1<<(j-1))][j-1]); } inline bool getpos(int l, int r, int &i, int &v) { if(l > r) return 0; int len = Log2[r-l+1]; rmq t = max(f[l][len], f[r-(1<<len)+1][len]); i = t.i, v = t.v; return 1; } } priority_queue<pa> q; int main() { scanf("%d%d%d%d", &n, &k, &L, &R); for (int i=1; i<=n; ++i) { scanf("%d", a+i); s[i] = s[i-1] + a[i]; } ST::init(n); for (int i=1; i<=n; ++i) { if(i+L-1>n) break; int l = i+L-1, r = min(i+R-1, n); int pos, va; ST::getpos(l, r, pos, va); q.push(pa(i, l, r, pos, va-s[i-1])); } ll ans = 0; for (int i=1; i<=k; ++i) { pa t = q.top(); ans = ans + t.v; q.pop(); int pos, val; if(ST::getpos(t.l, t.mx-1, pos, val)) q.push(pa(t.x, t.l, t.mx-1, pos, val-s[t.x-1])); if(ST::getpos(t.mx+1, t.r, pos, val)) q.push(pa(t.x, t.mx+1, t.r, pos, val-s[t.x-1])); } printf("%lld\n", ans); return 0; }