zoukankan      html  css  js  c++  java
  • Siano

    Description

    农夫Byteasar买了一片n亩的土地,他要在这上面种草。他在每一亩土地上都种植了一种独一无二的草,其中,第i亩土地的草每天会长高(a_i)厘米。Byteasar一共会进行(m)次收割,其中第i次收割在第(d_i)天,并把所有高度大于等于(b_i)的部分全部割去。Byteasar想知道,每次收割得到的草的高度总和是多少,你能帮帮他吗?

    Input

    第一行包含两个正整数 n,m, 分别表示亩数和收割次数。第二行包含n个正整数,其中第i个数为(a_i),依次表示每亩种植的草的生长能力。接下来m行,每行包含两个正整数(d_i,b_i)依次描述每次收割。

    Output

    输出 m行,每行一个整数,依次回答每次收割能得到的草的高度总和。

    Sample Input

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

    Sample Output

    6
    6
    18
    0

    Hint

    样例解释

    • 第 1天,草的高度分别为1,2,4,3,收割后变为1,1,1,1。
    • 第 2天,草的高度分别为 2,3,5,4,收割后变为 2,2,2,2。
    • 第 3天,草的高度分别为 3,4,6,5,收割后变为 0,0,0,0。
    • 第 4天,草的高度分别为 1,2,4,3 ,收割后变为 1,2,4,3。
      对于100的数据,(1≤n,m≤5×10^5,1≤a_i≤10^6,1≤d_i,b_i≤10^{12})
      数据保证(d_1<d_2<...<d_m),并且任何时刻没有任何一亩草的高度超过(10^{12})
      (来源:bzoj4293)

    Solution

    这是一道思维较简单,代码实现难的题目。线段树向我发起了挑衅......

    • 我们首先应该明白,对于生长速度已经确定的几种草,他们的高度应该具有与生长速度一样的单调性。
    • 那么我们先排一下序,所以我们每次割草时,只需要求这个数组后面一段草的割下来的高度和。高度和可以用(总高度-限制的高度×该段草的数量)得到。
    • 所以我们需要维护一些东西,去求割草的起始位置,割草时某一个区间(也就是割草起始位置到最后)草的总高度。
    • 这些东西是什么呢,在代码中我有解释了。

    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #define int long long
    #define L rt<<1
    #define R rt<<1|1
    using namespace std;
    const int maxn=5e5+5;
    template<typename T> void rd(T &x) {//快读写不写的吧,是找的别人的快读
    	x = 0; T f = 1; char ch = getchar();
    	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1;
    	for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
    	x *= f;
    }
    int n,m,a[maxn],t[maxn<<2],bgt[maxn<<2],spd[maxn<<2],mspd[maxn<<2],mn[maxn<<2],lazyd[maxn<<2],lazyb[maxn<<2];
    //bgt->开始重新生长的时间(begin time)spd->生长速度(speed) mspd->区间最小生长速度(min speed)用于求割草的起点 mn->区间最矮高度(min) 用于求割草的起点
    int ans;
    void P(int rt){//常规操作push up
            bgt[rt]=bgt[R];
    	t[rt]=t[L]+(bgt[rt]-bgt[L])*spd[L]+t[R];
    	mn[rt]=mn[L]+(bgt[R]-bgt[L])*mspd[L];
    	spd[rt]=spd[L]+spd[R];
    	mspd[rt]=mspd[L];
    }
    void U(int rt,int l,int r,int d,int b){//常规操作update,push down中调用
    	bgt[rt]=d+1;
    	t[rt]=(r-l+1)*b;
    	mn[rt]=b;
    	lazyd[rt]=d;
    	lazyb[rt]=b;
    }
    void Pd(int rt,int l,int r){//常规操作 push down
    	if(!lazyd[rt])return;
    	int mid=(l+r)>>1;
    	U(L,l,mid,lazyd[rt],lazyb[rt]);
    	U(R,mid+1,r,lazyd[rt],lazyb[rt]);
    	lazyd[rt]=lazyb[rt]=0;
    }
    void B(int rt,int l,int r){//常规操作build
    	t[rt]=mn[rt]=0;
    	bgt[rt]=1;
    	if(l==r){
    		spd[rt]=mspd[rt]=a[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	B(L,l,mid);
    	B(R,mid+1,r);
    	P(rt);
    	
    }
    int F(int rt,int l,int r,int d,int b){//find找割草起点
    	if(l==r){
    		if(mn[rt]+(d-bgt[rt]+1)*mspd[rt]>b)return l;
    		else return l+1;
    	}
    	Pd(rt,l,r);
    	int mid=(l+r)>>1;
    	if(mn[R]+(d-bgt[R]+1)*mspd[R]>b)return F(L,l,mid,d,b);
    	else return F(R,mid+1,r,d,b);
    }
    int Q(int rt,int l,int r,int x,int y,int d,int b){//常规操作query
    	if(x>y)return 0LL;
    	if(x<=l&&r<=y)return t[rt]+(d-bgt[rt]+1)*spd[rt]-(r-l+1)*b;
    	Pd(rt,l,r);
    	int mid=(l+r)>>1,ans=0;
    	if(x<=mid)ans+=Q(L,l,mid,x,y,d,b);
    	if(y >mid)ans+=Q(R,mid+1,r,x,y,d,b);
    	return ans;
    }
    void M(int rt,int l,int r,int x,int y,int d,int b){//常规操作modify
    	if(x>y)return;
    	if(x<=l&&r<=y){
    		U(rt,l,r,d,b);
    		return;
    	}
    	Pd(rt,l,r);
    	int mid=(l+r)>>1;
    	if(x<=mid)M(L,l,mid,x,y,d,b);
    	if(y >mid)M(R,mid+1,r,x,y,d,b);
    	P(rt);
    }
    signed main(){
    	//freopen("1.in","r",stdin);
    	rd(n);rd(m);
    	for(int i=1;i<=n;++i)rd(a[i]);
    	sort(a+1,a+1+n);
    	B(1,1,n);
    	for(int i=1,d,b,pos;i<=m;++i){
    		rd(d),rd(b);
    		pos=F(1,1,n,d,b);//查询割草的起点
    		ans=Q(1,1,n,pos,n,d,b);//割完草了,求被割的高度和(常规操作)
    		printf("%lld
    ",ans);
    		M(1,1,n,pos,n,d,b);//割完草了,修改被割的草的高度
    	}
    	return 0;
    }
    
  • 相关阅读:
    Leetcode 1489找到最小生成树李关键边和伪关键边
    Leetcode 113 路径总和 II
    hdu 1223 还是畅通工程
    hdu 1087 Super Jumping! Jumping! Jumping!
    hdu 1008 Elevator
    hdu 1037 Keep on Truckin'
    湖工oj 1241 畅通工程
    湖工oj 1162 大武汉局域网
    hdu 2057 A + B Again
    poj 2236 Wireless Network
  • 原文地址:https://www.cnblogs.com/Lour688/p/Siano.html
Copyright © 2011-2022 走看看