[BZOJ4293][PA2015]Siano
[BZOJ4293][PA2015]Siano
试题描述
农夫Byteasar买了一片n亩的土地,他要在这上面种草。
他在每一亩土地上都种植了一种独一无二的草,其中,第i亩土地的草每天会长高a[i]厘米。
Byteasar一共会进行m次收割,其中第i次收割在第d[i]天,并把所有高度大于等于b[i]的部分全部割去。Byteasar想知道,每次收割得到的草的高度总和是多少,你能帮帮他吗?
输入
第一行包含两个正整数n,m(1<=n,m<=500000),分别表示亩数和收割次数。
第二行包含n个正整数,其中第i个数为a[i](1<=a[i]<=1000000),依次表示每亩种植的草的生长能力。
接下来m行,每行包含两个正整数d[i],b[i](1<=d[i]<=10^12,0<=b[i]<=10^12),依次描述每次收割。
数据保证d[1]<d[2]<...<d[m],并且任何时刻没有任何一亩草的高度超过10^12。
输出
输出m行,每行一个整数,依次回答每次收割能得到的草的高度总和。
输入示例
4 4 1 2 4 3 1 1 2 2 3 0 4 4
输出示例
6 6 18 0
数据规模及约定
见“输入”
题解
可以发现,每次割完之后草的高度大小关系都是不变的,所以我们把草按照生长能力排序,然后就可以二分出每次割草的位置了,那么每次割草就是一个 [x, n] 的区间修改操作,线段树即可。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; #define LL long long LL read() { 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() { n = read(); int q = read(); 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; }
貌似加了输出优化比不加还慢。。。