BZOJ4293 Siano
題頭:
描述
農(nóng)夫Byteasar買了一片n畝的土地,他要在這上面種草。 他在每一畝土地上都種植了一種獨(dú)一無(wú)二的草,其中,第i畝土地的草每天會(huì)長(zhǎng)高a[i]厘米。 Byteasar一共會(huì)進(jìn)行m次收割,其中第i次收割在第d[i]天,并把所有高度大于等于b[i]的部分全部割去。Byteasar想知道,每次收割得到的草的高度總和是多少,你能幫幫他嗎?
Input
第一行包含兩個(gè)正整數(shù)n,m(1<=n,m<=500000),分別表示畝數(shù)和收割次數(shù)。 第二行包含n個(gè)正整數(shù),其中第i個(gè)數(shù)為ai,依次表示每畝種植的草的生長(zhǎng)能力。 接下來(lái)m行,每行包含兩個(gè)正整數(shù)d[i],bi,依次描述每次收割。 數(shù)據(jù)保證d[1] < d[2] <… < d[m],并且任何時(shí)刻沒(méi)有任何一畝草的高度超過(guò)10^12。
Output
輸出m行,每行一個(gè)整數(shù),依次回答每次收割能得到的草的高度總和。
樣例輸入
4 4
1 2 4 3
1 1
2 2
3 0
4 4
樣例輸出
6
6
18
0
仔細(xì)讀題
我們需要兩個(gè)標(biāo)記
一個(gè)mark進(jìn)行區(qū)間加的操作(mark維護(hù)天數(shù),實(shí)際增加的值是mark[ i ]*a[ i ])
還需要一個(gè)marks進(jìn)行區(qū)間更改為的操作
然后對(duì)于每次輸入
mark增加的值為這一次輸入的時(shí)間減上一次輸入的時(shí)間
然后我們維護(hù)兩個(gè)值:區(qū)間和和區(qū)間最大值(兩次區(qū)間和相減即使所求答案,區(qū)間最大值是方便進(jìn)行區(qū)間更改為的操作,因?yàn)檫@樣我們只需要下傳標(biāo)記到區(qū)間最大值大于b[ i ]的區(qū)間)
維護(hù)區(qū)間和需要把區(qū)間a的值的和乘上mark,區(qū)間最大值加上天數(shù)乘區(qū)間a的最大值;
我們只需要先從小到大排個(gè)序,保證單調(diào)性,這樣找到最后一個(gè)高度小于b[ i ]的位置,我們就可以直接把從這兒往后都打上標(biāo)記
代碼如下
//siano #include<bits/stdc++.h> using namespace std; #define ll long long inline ll read(){char ch;while((ch=getchar())<'0'||ch>'9'){;}ll res=ch-'0';while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-'0';return res; } long long a[500005],tre[2000007],mark[2000007],maxn[2000007],sum[500005],marks[2000007],d1; //tre:記錄區(qū)間和,sum int n,m,l[2000007],r[2000007]; inline ll max(ll a,ll b) {return a>b?a:b; } inline void buildtree(int p,int st,int end){l[p]=st,r[p]=end,mark[p]=0,marks[p]=-1; //marks初始化為-1,不能初始化為0(有可能是更改為0)if(st==end){tre[p]=maxn[p]=0;return;}int mid=(st+end)>>1;buildtree(p<<1,st,mid),buildtree((p<<1)+1,mid+1,end); } inline void pushup(int root) //向上傳遞 {maxn[root]=max(maxn[(root<<1)],maxn[(root<<1)+1]);tre[root]=tre[(root<<1)]+tre[(root<<1)+1]; } inline void pushnow(int root,ll v){ //用mark更改區(qū)間mark[root]+=v;tre[root]+=v*(sum[r[root]]-sum[l[root]-1]);maxn[root]+=v*a[r[root]]; } inline void pushnown(int root,ll k) //用marks更改區(qū)間 {marks[root]=k;maxn[root]=k;tre[root]=k*(r[root]-l[root]+1);mark[root]=0; //因?yàn)楦膮^(qū)間以后前面的操作打下的mark,對(duì)當(dāng)前答案不會(huì)有影響,所以把mark變?yōu)?; } inline void pushDown(int root) //向下傳遞 {if(marks[root]!=-1){pushnown((root<<1),marks[root]);pushnown((root<<1)+1,marks[root]);marks[root]=-1;}if(mark[root]){pushnow((root<<1),mark[root]);pushnow((root<<1)+1,mark[root]);mark[root]=0;} } inline void modify(int root,int ql,int qr,ll v){ //更改區(qū)間值if(ql>r[root]||qr<l[root])return;if(ql<=l[root]&&r[root]<=qr){pushnown(root,v);return;}pushDown(root);int mid=(l[root]+r[root])>>1;if(qr<=mid)modify((root<<1),ql,qr,v);else if(ql>mid)modify((root<<1)+1,ql,qr,v);else modify((root<<1),ql,mid,v),modify((root<<1)+1,mid+1,qr,v);pushup(root); } inline ll query(int root,ll v){ //查找第一個(gè)小于等于b[ i ]的位置 if(l[root]==r[root])return l[root];pushDown(root);if(maxn[(root<<1)]<=v)return query((root<<1)+1,v);return query((root<<1),v); }int main(){n=read(),m=read();for(int i=1;i<=n;i++){a[i]=read();}sort(a+1,a+1+n);buildtree(1,1,n);for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];d1=0;for(int i=1;i<=m;i++){ll d2=read(),b=read();maxn[1]+=(d2-d1)*a[n],tre[1]+=(d2-d1)*sum[n],mark[1]+=(d2-d1);if(maxn[1]<=b){puts("0"),d1=d2;continue;}ll res=tre[1];int pos=query(1,b);modify(1,pos,n,b);cout<<res-tre[1]<<'\n',d1=d2;}return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/stargazer-cyk/p/10366527.html
總結(jié)
以上是生活随笔為你收集整理的BZOJ4293 Siano的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: sha256算法
- 下一篇: 【深度学习torch——error】——