题面
Sol
求前缀和之后,每次枚举左端点,找到相应的区间最大值,丢到堆里面
每次取出一个就拿出来找下一个最大值再丢进去
那么就是要求区间第(k)大,主席树就好了
因为数组开小了和没开longlong,WA无数遍
我太菜了太菜了太菜了
# include <bits/stdc++.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(5e5 + 5);
IL ll Read(){
RG char c = getchar(); RG ll x = 0, z = 1;
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int n, k, L, R, a[_], rt[_], sz[_ * 20], cnt, ls[_ * 20], rs[_ * 20], o[_], len;
ll ans;
struct Data{
int v, l, kth;
IL bool operator <(RG Data B) const{ return v < B.v; }
};
priority_queue <Data> Q;
IL void Modify(RG int &x, RG int l, RG int r, RG int val){
sz[++cnt] = sz[x] + 1; ls[cnt] = ls[x]; rs[cnt] = rs[x]; x = cnt;
if(l == r) return;
RG int mid = (l + r) >> 1;
if(val <= mid) Modify(ls[x], l, mid, val);
else Modify(rs[x], mid + 1, r, val);
}
IL int Query(RG int A, RG int B, RG int l, RG int r, RG int kth){
if(l == r) return o[l];
RG int sum = sz[ls[A]] - sz[ls[B]], mid = (l + r) >> 1;
if(sum >= kth) return Query(ls[A], ls[B], l, mid, kth);
return Query(rs[A], rs[B], mid + 1, r, kth - sum);
}
int main(RG int argc, RG char* argv[]){
n = Read(); k = Read(); L = Read(); R = Read();
for(RG int i = 1; i <= n; ++i) a[i] = a[i - 1] + Read(), o[++len] = a[i];
sort(o + 1, o + len + 1); len = unique(o + 1, o + len + 1) - o - 1;
for(RG int i = 1; i <= n; ++i){
a[i] = lower_bound(o + 1, o + len + 1, a[i]) - o;
rt[i] = rt[i - 1];
Modify(rt[i], 1, len, a[i]);
}
for(RG int i = 1; i + L - 1 <= n; ++i){
RG int l = i + L - 1, r = min(n, i + R - 1), mx = Query(rt[r], rt[l - 1], 1, len, r - l + 1);
Q.push((Data){mx - o[a[i - 1]], i, r - l + 1});
}
for(RG int i = 1; i <= k; ++i){
RG Data x = Q.top(); Q.pop();
ans += x.v;
if(x.kth == 1) continue;
RG int l = x.l + L - 1, r = min(n, x.l + R - 1), mx = Query(rt[r], rt[l - 1], 1, len, x.kth - 1);
Q.push((Data){mx - o[a[x.l - 1]], x.l, x.kth - 1});
}
printf("%lld
", ans);
return 0;
}