【线段树】【二分】[PA2015][BZOJ4293]Siano
题目
Description
农夫Byteasar买了一片n亩的土地,他要在这上面种草。
他在每一亩土地上都种植了一种独一无二的草,其中,第i亩土地的草每天会长高a[i]厘米。
Byteasar一共会进行m次收割,其中第i次收割在第d[i]天,并把所有高度大于等于b[i]的部分全部割去。Byteasar想知道,每次收割得到的草的高度总和是多少,你能帮帮他吗?
Input
第一行包含两个正整数
第二行包含n个正整数,其中第i个数为
接下来m行,每行包含两个正整数
数据保证
Output
输出m行,每行一个整数,依次回答每次收割能得到的草的高度总和。
Sample Input
4 4
1 2 4 3
1 1
2 2
3 0
4 4
Sample Output
6
6
18
0
HINT
第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
分析
在任何时刻,生长速度较快的草的高度都不会低于生长速度较慢的草的高度。
我们把草按照生长速度排序,然后就可以用线段树来维护这些草的高度。
然后,我们每次在线段树中查找高度大于b的部分(也就是线段树上的二分),求出(高度-b)的和再减去,就可以得到答案。
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 500000
typedef long long LL;
int n,a[MAXN+10],m;
template<class T>
void Read(T &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
struct node{
LL a,sum,tag,ld,tagd,mx,mi;// a:生长速度的总和 sum:高度和 tag懒标记 tagd:打懒标记的时间 mx:区间最大草的高度 mi:区间最小草的高度
}tree[MAXN*4+10];
void build(int i,int l,int r){
tree[i].tag=-1;
if(l==r){
tree[i].a=a[l];
return;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build((i<<1)|1,mid+1,r);
tree[i].a=tree[i<<1].a+tree[(i<<1)|1].a;
}
inline void push_down(int i,int l,int r){
int mid=(l+r)>>1;
if(~tree[i].tag){
tree[i<<1].sum=tree[i].tag*(mid-l+1);
tree[i<<1].mi=tree[i<<1].mx=tree[(i<<1)|1].mi=tree[(i<<1)|1].mx=tree[i].tag;
tree[(i<<1)|1].sum=tree[i].tag*(r-mid);
tree[i<<1].tagd=tree[(i<<1)|1].tagd=tree[i<<1].ld=tree[(i<<1)|1].ld=tree[i].tagd;
tree[i<<1].tag=tree[(i<<1)|1].tag=tree[i].tag;
tree[i].tag=-1;
}
}
LL get_sum(int i,int l,int r,LL d,LL b){
LL ret;
tree[i].sum+=(d-tree[i].ld)*tree[i].a;
tree[i].mi+=a[l]*(d-tree[i].ld);
tree[i].mx+=a[r]*(d-tree[i].ld);
tree[i].ld=d;
if(tree[i].mx<=b)
return 0;
if(tree[i].mi>b){
ret=tree[i].sum-b*(r-l+1);
tree[i].tagd=tree[i].ld=d;
tree[i].tag=b;
tree[i].sum=(r-l+1)*b;
tree[i].mx=tree[i].mi=b;
return ret;
}
push_down(i,l,r);
int mid=(l+r)>>1;
ret=get_sum(i<<1,l,mid,d,b)+get_sum((i<<1)|1,mid+1,r,d,b);
tree[i].sum=tree[i<<1].sum+tree[(i<<1)|1].sum;
tree[i].mi=tree[i<<1].mi,tree[i].mx=tree[(i<<1)|1].mx;
return ret;
}
void read(){
Read(n),Read(m);
for(int i=1;i<=n;i++)
Read(a[i]);
sort(a+1,a+n+1);
build(1,1,n);
}
void solve(){
int i;
LL ans,d,b;
for(i=1;i<=m;i++){
Read(d),Read(b);
ans=get_sum(1,1,n,d,b);
printf("%lld\n",ans);
}
}
int main()
{
read();
solve();
}