【BZOJ4293】[PA2015]Siano 线段树

【BZOJ4293】[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个数为a[i](1<=a[i]<=1000000),依次表示每亩种植的草的生长能力。
接下来m行,每行包含两个正整数d[i],b[i](1<=d[i]<=10^12,0<=b[i]<=10^12),依次描述每次收割。
数据保证d[1]<d[2]<...<d[m],并且任何时刻没有任何一亩草的高度超过10^12。

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。

题解:有一个容易发现的性质:长得快的草永远不会比长得慢的草矮。

所以先按ai排序,然后每次只需要二分一个边界,长得比这个边界快的草都会被割掉。然后用线段树维护即可。

但是具体实现不是那么方便,我们的线段树需要维护:带系数的区间加,区间赋值,区间求和,区间求最大值。细节还是看代码吧~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;
typedef long long ll;
const int maxn=500010;
int n,m;
ll A[maxn],B,D[maxn],s[maxn<<2],sm[maxn<<2],siz[maxn<<2],ts[maxn<<2],tag[maxn<<2];
void pushup(int x)
{
	s[x]=s[lson]+s[rson],sm[x]=min(sm[lson],sm[rson]);
}
void pushdown(int l,int r,int x)
{
	int mid=l+r>>1;
	if(~tag[x])
	{
		ts[lson]=ts[rson]=0,tag[lson]=tag[rson]=sm[lson]=sm[rson]=tag[x];
		s[lson]=(mid-l+1)*tag[x],s[rson]=(r-mid)*tag[x];
		tag[x]=-1;
	}
	if(ts[x])
	{
		ts[lson]+=ts[x],ts[rson]+=ts[x];
		s[lson]+=siz[lson]*ts[x],sm[lson]+=A[l]*ts[x],s[rson]+=siz[rson]*ts[x],sm[rson]+=A[mid+1]*ts[x];
		ts[x]=0;
	}
}
void build(int l,int r,int x)
{
	tag[x]=-1;
	if(l==r)
	{
		siz[x]=A[l];
		return ;
	}
	int mid=l+r>>1;
	build(l,mid,lson),build(mid+1,r,rson);
	siz[x]=siz[lson]+siz[rson];
}
ll updata(int l,int r,int x,int a,int b,ll c)
{
	if(a<=l&&r<=b)
	{
		ll ret=s[x]-(r-l+1)*c;
		ts[x]=0,sm[x]=tag[x]=c,s[x]=(r-l+1)*c;
		return ret;
	}
	pushdown(l,r,x);
	int mid=l+r>>1;
	ll ret=0;
	if(a<=mid)	ret+=updata(l,mid,lson,a,b,c);
	if(b>mid)	ret+=updata(mid+1,r,rson,a,b,c);
	pushup(x);
	return ret;
}
int getpre(int l,int r,int x,ll a)
{
	if(sm[x]>=a)	return l-1;
	if(l==r)	return l;
	pushdown(l,r,x);
	int mid=l+r>>1;
	if(sm[rson]<a)	return getpre(mid+1,r,rson,a);
	return getpre(l,mid,lson,a);
}
ll rd()
{
	ll ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),m=rd();
	int i;
	for(i=1;i<=n;i++)	A[i]=rd();
	sort(A+1,A+n+1);
	build(1,n,1);
	for(i=1;i<=m;i++)
	{
		D[i]=rd(),B=rd();
		ts[1]+=D[i]-D[i-1],s[1]+=siz[1]*(D[i]-D[i-1]),sm[1]+=A[1]*(D[i]-D[i-1]);
		int a=getpre(1,n,1,B);
		if(a<n)	printf("%lld
",updata(1,n,1,a+1,n,B));
		else	printf("0
");
	}
	return 0;
}//4 4 1 2 4 3 1 1 2 2 3 0 4 4
原文地址:https://www.cnblogs.com/CQzhangyu/p/7327594.html