[PA2015]Siano
描述
Description
农夫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
提示
第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。
Source
By Claris
标签
BZOJ4293 电子科大春季营考试最后一题
分析
令人窒息……刚刚全部都认认真真地写了题解,然后电脑莫名重启,csdn居然没有帮我保存……啊啊啊,差评
算了,再来一遍
用线段树搞:
1.长草变成区间加
2.查询区间内刚好小于等于某个数的下标
3.大于割草高度的全部区间覆盖成割草高度,然后比较覆盖前后的区间和就行了。
要注意长草的时候,lazy(加标记)维护的是生长的天数,所以区间和的话应该是这个天数乘以相应的生长高度(这个高度,可以用前缀和预处理,表现在代码中就是
t
o
t
tot
tot数组)
原谅水了一波,电脑三次重启,实在令人窒息,没心情写了
代码
#include<bits/stdc++.h>
#define in read()
#define lc (k<<1)
#define rc (k<<1)|1
#define N 500009
#define int long long
#define ll long long
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
int n,m,a[N];
ll maxn[N<<2],sum[N<<2],lzy[N<<2],tag[N<<2];
ll tot[N];
void Cover(int k,int l,int r,ll v){
lzy[k]=0;
tag[k]=maxn[k]=v;
sum[k]=(r-l+1)*v;
}
void Add(int k,int l,int r,ll v){
lzy[k]+=v;
maxn[k]+=v*a[r];sum[k]+=(tot[r]-tot[l-1])*v;
}
void pushdown(int k,int l,int r){
int mid=l+r>>1;
if(tag[k]!=-1) Cover(lc,l,mid,tag[k]),Cover(rc,mid+1,r,tag[k]),tag[k]=-1;
if(lzy[k]) Add(lc,l,mid,lzy[k]),Add(rc,mid+1,r,lzy[k]),lzy[k]=0;
}
int find(int k,int l,int r,ll x){
if(l==r) return l;
pushdown(k,l,r);
int mid=l+r>>1;
if(maxn[lc]>=x) return find(lc,l,mid,x);/
else return find(rc,mid+1,r,x);
}
void pushup(int k){
sum[k]=sum[lc]+sum[rc];
maxn[k]=max(maxn[lc],maxn[rc]);
}
void modify(int k,int l,int r,int x,int y,ll v){
if(x<=l&&r<=y){
Cover(k,l,r,v);return;
}
pushdown(k,l,r);
int mid=l+r>>1;
if(x<=mid) modify(lc,l,mid,x,y,v);
if(y>mid) modify(rc,mid+1,r,x,y,v);
pushup(k);
}
signed main(){
n=in;m=in;
int i,j,k;
memset(tag,-1,sizeof(tag));
tot[0]=0;
for(i=1;i<=n;++i) a[i]=in;
sort(a+1,a+n+1);
for(i=1;i<=n;++i) tot[i]=tot[i-1]+a[i];
int d1=0,d2;
ll b;
for(i=1;i<=m;++i){
d2=in;scanf("%lld",&b);
lzy[1]+=1ll*(d2-d1);sum[1]+=1ll*(d2-d1)*tot[n];maxn[1]+=1ll*a[n]*(d2-d1);
if(maxn[1]<=b){printf("0\n");d1=d2;continue; }
ll ans=sum[1];
int pos=find(1,1,n,b);
modify(1,1,n,pos,n,b);//qujian fuzhi
cout<<ans-sum[1]<<'\n';
d1=d2;
}
return 0;
}