【有趣的有趣的家庭菜园】题解

分析

设f[i]指1i没有比i更高的草是,1i的收益。
显然转移为,当h[j]<=h[i]$$f[i]=max(f[j]-sum_{j<k<i 且 h[k]>h[i] }{c[k]})+p[i]$$
然后设g[i]指in没有比i更高的草是,in的收益。转移同上。答案就是max(f[i]+g[i]-p[i]),O(n^3),超时。
如何优化呢?由于n<=100000,就离散化h,以高度搞个有标记线段树,记录$$max(f[j]-sum_{j<k<i 且 h[k]>h[i] }{c[k]})$$。然后每次把小于等于h[i]的线段树的最大值取出来,把f[i]放入线段树,再把小于h[i]的都减去c[i]。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const long long maxlongint=2147483647;
using namespace std;
long long tree[400000],f[200000],g[200000],n,m,ans,tot,h[200000],p[200000],c[200000],bef[200000],reh[200000],dee[400000];
void q(long long l,long long r)
{
	long long i=l,j=r,mid=reh[(l+r)/2],e;
	while(i<j)
	{
		while(reh[i]<mid) i++;
		while(reh[j]>mid) j--;
		if(i<=j)
		{
			e=reh[i];
			reh[i]=reh[j];
			reh[j]=e;
			e=bef[i];
			bef[i]=bef[j];
			bef[j]=e;
			i++;
			j--;
		}
	}
	if(i<r) q(i,r);
	if(l<j) q(l,j);
}
long long disc()
{
	long long k;
	q(1,n);
	k=0;
	for(long long i=1;i<=n;i++)
	{
		if(reh[i]!=reh[i-1])
			k++;
		h[bef[i]]=k;
	}
}
long long find(long long v,long long l,long long r,long long x,long long y)
{ 
	if(l==x && r==y)
	{
		return tree[v];
	}
	if(tree[v*2]!=tree[0])
	{
		tree[v*2]-=dee[v];
		dee[v*2]+=dee[v];
	}
	else
	{
		tree[v*2]=-dee[v];
		dee[v*2]+=dee[v];
	}
	if(tree[v*2+1]!=tree[0])
	{
		tree[v*2+1]-=dee[v];
		dee[v*2+1]+=dee[v];
	}
	else
	{
		tree[v*2+1]=-dee[v];
		dee[v*2+1]+=dee[v];
	}
	dee[v]=0;
	long long mid=(l+r)/2,t,t1;
	if(y<=mid)
	{
		return find(v*2,l,mid,x,y);
	}
			else
				if(x>mid)
					return find(v*2+1,mid+1,r,x,y);
						else 
						{
							return max(find(v*2,l,mid,x,mid),find(v*2+1,mid+1,r,mid+1,y));
						}
	return t;
}
long long put(long long v,long long l,long long r,long long hi,long long pu)
{
	if(l==r)
	{
		tree[v]=max(tree[v],pu);
		return 0;
	}
	if(tree[v*2]!=tree[0])
	{
		tree[v*2]-=dee[v];
		dee[v*2]+=dee[v];
	}
	else
	{
		tree[v*2]=-dee[v];
		dee[v*2]+=dee[v];
	}
	if(tree[v*2+1]!=tree[0])
	{
		tree[v*2+1]-=dee[v];
		dee[v*2+1]+=dee[v];
	}
	else
	{
		tree[v*2+1]=-dee[v];
		dee[v*2+1]+=dee[v];
	}
	dee[v]=0;
	long long mid=(l+r)/2;
	if(hi<=mid)
	{	
		put(v*2,l,mid,hi,pu);
		tree[v]=max(tree[v*2+1],tree[v*2]);
	}
	else
	{
		put(v*2+1,mid+1,r,hi,pu);
		tree[v]=max(tree[v*2],tree[v*2+1]);	
	}
	tree[v]=max(tree[v*2],tree[v*2+1]);
}
long long de(long long v,long long l,long long r,long long x,long long y,long long d)
{
	if(l==x && r==y)
	{
		dee[v]+=d;
		tree[v]-=d;
		return 0;
	}
	if(tree[v*2]!=tree[0])
	{
		tree[v*2]-=dee[v];
		dee[v*2]+=dee[v];
	}
	else
	{
		tree[v*2]=-dee[v];
		dee[v*2]+=dee[v];
	}
	if(tree[v*2+1]!=tree[0])
	{
		tree[v*2+1]-=dee[v];
		dee[v*2+1]+=dee[v];
	}
	else
	{
		tree[v*2+1]=-dee[v];
		dee[v*2+1]+=dee[v];
	}
	dee[v]=0;
	long long mid=(l+r)/2;
	if(y<=mid)
		de(v*2,l,mid,x,y,d);
			else
				if(x>mid)
					de(v*2+1,mid+1,r,x,y,d);
						else de(v*2,l,mid,x,mid,d),de(v*2+1,mid+1,r,mid+1,y,d);
	tree[v]=max(tree[v*2],tree[v*2+1]);	
}
int main()
{
	scanf("%lld
",&n);
	long long i,j,k;
	for(i=1;i<=n;i++)
	{
		scanf("%lld%lld%lld
",&reh[i],&p[i],&c[i]);
		bef[i]=i;
	}
	disc();
	memset(tree,200,sizeof(tree));
	put(1,0,n,0,0);
	memset(dee,0,sizeof(dee));
	for(i=1;i<=n;i++)
	{
		f[i]=find(1,0,n,0,h[i])+p[i];
		put(1,0,n,h[i],f[i]);
		
		de(1,0,n,0,h[i]-1,c[i]);
	}
	memset(tree,200,sizeof(tree));
	put(1,0,n,0,0);
	memset(dee,0,sizeof(dee));
	ans=0;
	for(i=n;i>=1;i--)
	{
		g[i]=find(1,0,n,0,h[i])+p[i];
		put(1,0,n,h[i],g[i]);
		de(1,0,n,0,h[i]-1,c[i]);
	}
    for(i=1;i<=n;i++)
    	ans=max(ans,f[i]-p[i]+g[i]);
	printf("%lld
",ans);
}




原文地址:https://www.cnblogs.com/chen1352/p/9008558.html