【题目】
题目描述:
农夫 Byteasar 买了一片 n n n 亩的土地,他要在这上面种草。
他在每一亩土地上都种植了一种独一无二的草,其中,第 i i i 亩土地的草每天会长高 a i a_i ai 厘米。
Byteasar 一共会进行 m m m 次收割,其中第 i i i 次收割在第 d i d_i di 天,并把所有高度大于等于 b i b_i bi 的部分全部割去。Byteasar 想知道,每次收割得到的草的高度总和是多少,你能帮帮他吗?
输入格式:
第一行包含两个正整数 n , m ( 1 ≤ n , m ≤ 500000 ) n,m(1≤n,m≤500000) n,m(1≤n,m≤500000),分别表示亩数和收割次数。
第二行包含 n n n 个正整数,其中第 i i i 个数为 a i ( 1 ≤ a i ≤ 1000000 ) a_i(1≤a_i≤1000000) ai(1≤ai≤1000000),依次表示每亩种植的草的生长能力。
接下来 m m m 行,每行包含两个正整数 d i , b i ( 1 ≤ d i ≤ 1 0 12 , 0 ≤ b i ≤ 1 0 12 ) d_i,b_i(1≤d_i≤10^{12},0≤b_i≤10^{12}) di,bi(1≤di≤1012,0≤bi≤1012),依次描述每次收割。
数据保证 d 1 < d 2 < . . . < d m d_1<d_2<...<d_m d1<d2<...<dm,并且任何时刻没有任何一亩草的高度超过 1 0 12 10^{12} 1012。
输出格式:
输出 m m m 行,每行一个整数,依次回答每次收割能得到的草的高度总和。
样例数据:
输入
4 4
1 2 4 3
1 1
2 2
3 0
4 4
输出
6
6
18
0
提示:
第
1
1
1 天,草的高度分别为
1
,
2
,
4
,
3
1,2,4,3
1,2,4,3,收割后变为
1
,
1
,
1
,
1
1,1,1,1
1,1,1,1。
第
2
2
2 天,草的高度分别为
2
,
3
,
5
,
4
2,3,5,4
2,3,5,4,收割后变为
2
,
2
,
2
,
2
2,2,2,2
2,2,2,2。
第
3
3
3 天,草的高度分别为
3
,
4
,
6
,
5
3,4,6,5
3,4,6,5,收割后变为
0
,
0
,
0
,
0
0,0,0,0
0,0,0,0。
第
4
4
4 天,草的高度分别为
1
,
2
,
4
,
3
1,2,4,3
1,2,4,3,收割后变为
1
,
2
,
4
,
3
1,2,4,3
1,2,4,3。
【分析】
首先,我们要知道一个东西,即若 a i > a j a_i>a_j ai>aj,那么在任意时间, h i h_i hi 是始终大于 h j h_j hj 的
那么我们不妨对数组 a a a 进行排序,排序后的草的高度在任意时间内是单调不减的
那么对于每次的询问 d i d_i di,所有草都长了 d i − d i − 1 d_i-d_{i-1} di−di−1 的时间,这个可以用预处理出前缀和,然后用区间加搞定,而对于 b i b_i bi,由于此时高度一定是单调不减的,可以二分找出第一个要割的位置(在线段树上找),然后统计答案后用区间覆盖
所以这道题就转变成了区间加,区间覆盖的简单问题(由于区间和只用返回 s u m r o o t sum_{root} sumroot,连区间和都不用写)
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500005
#define ll long long
using namespace std;
int a[N];
ll d[N],b[N],s[N],sum[N<<2],Max[N<<2],add[N<<2],mark[N<<2];
void Pushup(int root)
{
sum[root]=sum[root<<1]+sum[root<<1|1];
Max[root]=max(Max[root<<1],Max[root<<1|1]);
}
void Cover(int root,int l,int r,ll val)
{
Max[root]=val;
sum[root]=val*(r-l+1);
add[root]=0,mark[root]=val;
}
void Add(int root,int l,int r,ll val)
{
add[root]+=val;
Max[root]+=val*a[r];
sum[root]+=val*(s[r]-s[l-1]);
}
void Pushdown(int root,int l,int r,int mid)
{
if(mark[root]!=-1) Cover(root<<1,l,mid,mark[root]),Cover(root<<1|1,mid+1,r,mark[root]);
if(add[root]) Add(root<<1,l,mid,add[root]),Add(root<<1|1,mid+1,r,add[root]);
add[root]=0,mark[root]=-1;
}
int find(int root,int l,int r,ll x)
{
if(l==r)return l;
int mid=(l+r)>>1;
Pushdown(root,l,r,mid);
if(x<=Max[root<<1]) return find(root<<1,l,mid,x);
return find(root<<1|1,mid+1,r,x);
}
void Modify(int root,int l,int r,int x,int y,ll val)
{
if(l>=x&&r<=y)
{
Cover(root,l,r,val);
return;
}
int mid=(l+r)>>1;
Pushdown(root,l,r,mid);
if(x<=mid) Modify(root<<1,l,mid,x,y,val);
if(y>mid) Modify(root<<1|1,mid+1,r,x,y,val);
Pushup(root);
}
int main()
{
int n,m,i;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
for(i=1;i<=n;++i)
s[i]=s[i-1]+a[i];
for(i=1;i<=m;++i)
{
scanf("%lld%lld",&d[i],&b[i]);
Add(1,1,n,d[i]-d[i-1]);ll ans=sum[1];
if(Max[1]<=b[i]){printf("0\n");continue;}
int pos=find(1,1,n,b[i]);
Modify(1,1,n,pos,n,b[i]);
printf("%lld\n",ans-sum[1]);
}
return 0;
}