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

貌似加了输出优化比不加还慢。。。

posted @ 2017-04-01 10:44  xjr01  阅读(207)  评论(0编辑  收藏  举报