[BZOJ4293][PA2015]Siano

Byteasar一共会进行m次收割，其中第i次收割在第d[i]天，并把所有高度大于等于b[i]的部分全部割去。Byteasar想知道，每次收割得到的草的高度总和是多少，你能帮帮他吗？

4 4
1 2 4 3
1 1
2 2
3 0
4 4

6
6
18
0

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define LL long long

LL x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}

#define maxn 500010

int n, A[maxn];
LL tagd[maxn<<2], tagh[maxn<<2], sumv[maxn<<2], minv[maxn<<2], maxv[maxn<<2], pre[maxn];

void maintain(int o, int l, int r) {
int lc = o << 1, rc = lc | 1;
if(!tagd[o]) sumv[o] = sumv[lc] + sumv[rc], minv[o] = minv[lc], maxv[o] = maxv[rc];
else {
sumv[o] = -(pre[r] - pre[l-1]) * tagd[o] + tagh[o] * (r - l + 1);
minv[o] = -tagd[o] * A[l] + tagh[o];
maxv[o] = -tagd[o] * A[r] + tagh[o];
}
return ;
}
void pushdown(int o, int l, int r) {
if(l == r) return maintain(o, l, r);
if(!tagd[o]) return maintain(o, l, r);
//	puts("real pushdown");
int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
tagd[lc] = tagd[rc] = tagd[o];
tagh[lc] = tagh[rc] = tagh[o];
sumv[lc] = -(pre[mid] - pre[l-1]) * tagd[o] + tagh[o] * (mid - l + 1);
sumv[rc] = -(pre[r] - pre[mid]) * tagd[o] + tagh[o] * (r - mid);
minv[lc] = -tagd[o] * A[l] + tagh[o];
minv[rc] = -tagd[o] * A[mid+1] + tagh[o];
maxv[lc] = -tagd[o] * A[mid] + tagh[o];
maxv[rc] = -tagd[o] * A[r] + tagh[o];
tagd[o] = tagh[o] = 0;
return maintain(o, l, r);
}
LL query(int o, int l, int r, LL day, LL hei) {
pushdown(o, l, r);
if(minv[o] + day * A[l] >= hei) {
//		printf("%d [%d, %d]: %lld\n", o, l, r, minv[o] + day * A[l]);
LL ans = sumv[o] + day * (pre[r] - pre[l-1]) - hei * (r - l + 1);
tagd[o] = day; tagh[o] = hei;
return maintain(o, l, r), ans;
}
if(l == r) return maintain(o, l, r), 0;
int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
LL ans = query(rc, mid + 1, r, day, hei);
if(maxv[lc] + day * A[mid] >= hei) ans += query(lc, l, mid, day, hei);
return maintain(o, l, r), ans;
}

#define maxlen 10000010
char Out[maxlen];
int num[20], cntn, olen;

int main() {
for(int i = 1; i <= n; i++) A[i] = read();
sort(A + 1, A + n + 1);
for(int i = 1; i <= n; i++) pre[i] = pre[i-1] + A[i];
while(q--) {
LL d = read(), h = read(), tmp = query(1, 1, n, d, h);
if(tmp) {
cntn = 0; while(tmp) num[cntn++] = tmp % 10, tmp /= 10;
for(int i = cntn - 1; i >= 0; i--) Out[olen++] = num[i] + '0';
} else Out[olen++] = '0';
Out[olen++] = '\n';
}
Out[--olen] = '\0';
puts(Out);

return 0;
}