zoukankan      html  css  js  c++  java
  • [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
    ", 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++] = '
    ';
    	}
    	Out[--olen] = '';
    	puts(Out);
    	
    	return 0;
    }
    

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

  • 相关阅读:
    142. 环形链表 II
    59. 螺旋矩阵 II
    996. 正方形数组的数目
    1323. 6 和 9 组成的最大数字
    面试题 17.14. 最小K个数
    389. 找不同
    1103. 分糖果 II
    背景透明度
    css3-新属性-用户界面
    响应式布局-基础结构
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6654945.html
Copyright © 2011-2022 走看看