BZOJ4239(线段树)
一道权限题
题面
描述
农夫Byteasar买了一片n亩的土地,他要在这上面种草。 他在每一亩土地上都种植了一种独一无二的草,其中,第i亩土地的草每天会长高a[i]厘米。 Byteasar一共会进行m次收割,其中第i次收割在第d[i]天,并把所有高度大于等于b[i]的部分全部割去。Byteasar想知道,每次收割得到的草的高度总和是多少,你能帮帮他吗?
Input
第一行包含两个正整数n,m(1<=n,m<=500000),分别表示亩数和收割次数。 第二行包含n个正整数,其中第i个数为ai,依次表示每亩种植的草的生长能力。 接下来m行,每行包含两个正整数d[i],bi,依次描述每次收割。 数据保证d[1] < d[2] <… < d[m],并且任何时刻没有任何一亩草的高度超过10^12。
Output
输出m行,每行一个整数,依次回答每次收割能得到的草的高度总和。
样例输入
4 4
1 2 4 3
1 1
2 2
3 0
4 4
样例输出
6
6
18
0
思想是比较奇妙的。
仔细读题,我们发现草的高度成一个单调性(因为每株草每天的生长量是一定的),考虑把草sort排序,那么每次先找到第一个大于b的草,从它开始后面的草都要被割
维护这样一些信息:
day:从上一次收割到这一次过去的天数
now:当前草的高度(每一次割草后那一串的草的高度都是b,那么对应区间now为b)
ans:区间草高度和
maxx:区间最高草的高度(对于每一次操作,如果最高草的高度都小于等于b,就可以不操作了)
标记下传时,先传now,再传day(类比于赋值标记和加标记)。
#include<bits/stdc++.h> #define LL long long #define N 500003 using namespace std; LL read() { LL x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } LL a[N],sum[N]; LL lc[N<<2],rc[N<<2],ans[N<<2],maxx[N<<2]; LL day[N<<2],now[N<<2]; LL ndnum=0; void pushup(LL k) { maxx[k]=max(maxx[lc[k]],maxx[rc[k]]); ans[k]=ans[lc[k]]+ans[rc[k]]; } void build(LL k,LL l,LL r) { if(l==r){now[k]=-1;return;} LL mid=(l+r)>>1; build(lc[k]=++ndnum,l,mid); build(rc[k]=++ndnum,mid+1,r); pushup(k); } void push1(LL k,LL l,LL r,LL v)//now的下传 { now[k]=v; maxx[k]=v; ans[k]=(r-l+1)*v;//相当于直接覆盖 day[k]=0;//当前值变了,存的天数也就没什么用了 } void push2(LL k,LL l,LL r,LL v)//day的下传 { day[k]+=v; ans[k]+=(sum[r]-sum[l-1])*v; maxx[k]+=v*a[r]; } void pushdown(LL k,LL l,LL r) { LL mid=(l+r)>>1; if(now[k]!=-1) { push1(lc[k],l,mid,now[k]); push1(rc[k],mid+1,r,now[k]); now[k]=-1; } if(day[k]) { push2(lc[k],l,mid,day[k]); push2(rc[k],mid+1,r,day[k]); day[k]=0; } } void modify(LL k,LL L,LL R,LL l,LL r,LL v) { if(L>=l&&R<=r) { push1(k,L,R,v); return; } LL mid=(L+R)>>1; pushdown(k,L,R); if(l<=mid)modify(lc[k],L,mid,l,r,v); if(r>mid)modify(rc[k],mid+1,R,l,r,v); pushup(k); } LL query(LL k,LL l,LL r,LL v) { if(l==r)return l; LL mid=(l+r)>>1; pushdown(k,l,r); if(maxx[lc[k]]<=v)return query(rc[k],mid+1,r,v); else return query(lc[k],l,mid,v); } int main() { LL n=read(),m=read(); build(1,1,n); for(int i=1;i<=n;++i)a[i]=read(); sort(a+1,a+1+n); for(int i=1;i<=n;++i) sum[i]=a[i]+sum[i-1]; LL d1=0;LL d2; while(m--) { d2=read();LL b=read(); day[1]+=d2-d1;maxx[1]+=(d2-d1)*a[n];ans[1]+=sum[n]*(d2-d1); d1=d2; if(maxx[1]<=b) { printf("0\n"); continue; } LL res=ans[1]; LL pos=query(1,1,n,b); modify(1,1,n,pos,n,b); printf("%lld\n",res-ans[1]); } }