【有趣的有趣的家庭菜园】题解
分析
设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",&n);
long long i,j,k;
for(i=1;i<=n;i++)
{
scanf("%lld%lld%lld\n",&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\n",ans);
}