【题目】
题目描述:
农夫 Byteasar 买了一片 nnn 亩的土地,他要在这上面种草。
他在每一亩土地上都种植了一种独一无二的草,其中,第 iii 亩土地的草每天会长高 aia_iai 厘米。
Byteasar 一共会进行 mmm 次收割,其中第 iii 次收割在第 did_idi 天,并把所有高度大于等于 bib_ibi 的部分全部割去。Byteasar 想知道,每次收割得到的草的高度总和是多少,你能帮帮他吗?
输入格式:
第一行包含两个正整数 n,m(1≤n,m≤500000)n,m(1≤n,m≤500000)n,m(1≤n,m≤500000),分别表示亩数和收割次数。
第二行包含 nnn 个正整数,其中第 iii 个数为 ai(1≤ai≤1000000)a_i(1≤a_i≤1000000)ai(1≤ai≤1000000),依次表示每亩种植的草的生长能力。
接下来 mmm 行,每行包含两个正整数 di,bi(1≤di≤1012,0≤bi≤1012)d_i,b_i(1≤d_i≤10^{12},0≤b_i≤10^{12})di,bi(1≤di≤1012,0≤bi≤1012),依次描述每次收割。
数据保证 d1<d2<...<dmd_1<d_2<...<d_md1<d2<...<dm,并且任何时刻没有任何一亩草的高度超过 101210^{12}1012。
输出格式:
输出 mmm 行,每行一个整数,依次回答每次收割能得到的草的高度总和。
样例数据:
输入
4 4
1 2 4 3
1 1
2 2
3 0
4 4
输出
6
6
18
0
提示:
第 111 天,草的高度分别为 1,2,4,31,2,4,31,2,4,3,收割后变为 1,1,1,11,1,1,11,1,1,1。
第 222 天,草的高度分别为 2,3,5,42,3,5,42,3,5,4,收割后变为 2,2,2,22,2,2,22,2,2,2。
第 333 天,草的高度分别为 3,4,6,53,4,6,53,4,6,5,收割后变为 0,0,0,00,0,0,00,0,0,0。
第 444 天,草的高度分别为 1,2,4,31,2,4,31,2,4,3,收割后变为 1,2,4,31,2,4,31,2,4,3。
【分析】
首先,我们要知道一个东西,即若 ai>aja_i>a_jai>aj,那么在任意时间,hih_ihi 是始终大于 hjh_jhj 的
那么我们不妨对数组 aaa 进行排序,排序后的草的高度在任意时间内是单调不减的
那么对于每次的询问 did_idi,所有草都长了 di−di−1d_i-d_{i-1}di−di−1 的时间,这个可以用预处理出前缀和,然后用区间加搞定,而对于 bib_ibi,由于此时高度一定是单调不减的,可以二分找出第一个要割的位置(在线段树上找),然后统计答案后用区间覆盖
所以这道题就转变成了区间加,区间覆盖的简单问题(由于区间和只用返回 sumrootsum_{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;
}