4296. 【NOIP2015模拟11.2】有趣的有趣的家庭菜园

Description

职业经营家庭菜园的JOI君每年在自家的田地中种植一种叫做IOI草的植物。IOI草的种子在冬天被播下,春天会发芽并生长至一个固定的高度。到了秋天,一些IOI草会结出美丽的果实,并被收获,其他的IOI草则会在冬天枯萎。
JOI君的田地沿东西方向被划分为N个区域,从西侧开始的第i个区域中种植着IOI草i。在第i个区域种植的IOI草,在春天的时候高度会生长至Hi,此后便不再生长。如果IOI草i会结出果实,那么将会获得Pi的收益,否则没有收益。
春天到了,查看田地样子的JOI君决定拔掉一些种植的IOI草,使利益最大化。拔掉IOI草i需要Ci的花销,拔掉的IOI草会立刻枯萎。IOI草只能在春天被拔掉,夏天和秋天不能拔掉IOI草。
IOI草是一种非常依靠阳光的植物,如果在夏天某个区域的IOI草的东侧和西侧都有比它高的IOI草存在,那么这株IOI草在秋天便不会结出果实。换句话说,为了让没有被拔掉的IOI草i在秋天结出果实,到了夏天的时候,以下两个条件至少满足一个:
1.对于任意1<=j<=i-1,Hj<=Hi或IOI草j已经被拔除
2.对于任意i+1<=j<=N,Hj<=Hi或IOI草j已经被拔除
用最终收获的果实的总价格减掉拔除IOI草的花销的总和,即为JOI君的收益。那么JOI君能从IOI草中获取的最大利益到底有多少呢?

Input

第一行一个正整数N,表示田地被分为了N个区域。
接下来N行,第i行(1<=i<=N)三个空白分割的正整数Hi,Pi,Ci,表示第i株IOI草在春天时高度会生长至Hi,秋天收获的果实的价格为Pi,拔除所需费用为Ci。

Output

输出一行一个整数,表示JOI君能获得的最大利益

Sample Input

7
22 60 30
46 40 30
36 100 50
11 140 120
38 120 20
24 90 60
53 50 20

Sample Output

320
【HINT】
拔除IOI草2和IOI草7,剩余的IOI草如下图所示:

IOI草1、3、5、6的果实价格分别为60、100、120、90,拔除IOI草2和IOI草7的花销分别为30、20,总收益为320,这是所有方案中的最大值。

Data Constraint

对于30%的数据,N<=20
对于45%的数据,N<=300
对于60%的数据,N<=5000
对于100%的数据:
3<=N<=10^5
1<=Hi<=10^9 (1<=i<=N)
1<=Pi<=10^9 (1<=i<=N)
1<=Ci<=10^9 (1<=i<=N)

Solution

最优答案呈三角形(中间高两边低)。
对于前后过做一遍。
设f[i]表示从前(或后)往后(或前)做到i的最优答案。
f[i]=p[ i ]+ max{ f[ j ] - sigma( cost[k], k | j<k<i&&h[k]>h[i] ) }
可以转换一下,直接删去比所有比 j 高的即可。
因为:如果 i 想从 j 转移过来:
1.如果 h[ k ] >h[ i ]>h[ j ]
那么k必须要删去。

2.如果 h[ i ]>h[ k ]>h[ j ]
因为k>j,所以我们相当于已经让i从k转移过来过一次了,即k可以转移到 i ,且包含了j的答案,所以一定比j优,这时删不删掉k对最右答案没有影响。

综上,可以把所有的比j高的直接删掉。
反过来,每次做完i的时候,把f[ i ]放进h[ i ]的线段树里面,然后把0~h[i]-1的高度的线段树里的值全部减去cost[ i ]。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define L x<<1
#define R L|1
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define ll long long
#define N 300010
using namespace std;
ll a[N],n,rk[N],cnt=0;
ll v[N],c[N],s[N],f[N],g[N],tr[N*5],lzy[N*5],ans;
struct node{ll v,id;}h[N];
I cmp(node x,node y){return x.v<y.v;}
void down(I x){
	if(!lzy[x]) return;
	tr[L]+=lzy[x],tr[R]+=lzy[x];
	lzy[L]+=lzy[x],lzy[R]+=lzy[x];
	lzy[x]=0;
}
void cg(I x,I l,I r,I k,ll val){
	if(l==r){tr[x]=max(tr[x],val);return;}
	down(x);
	I M=l+r>>1;
	if(k<=M) cg(L,l,M,k,val);
	else cg(R,M+1,r,k,val);
	tr[x]=max(tr[L],tr[R]);
}
ll qry(I x,I l,I r,I l2,I r2){
	if(l==l2&&r==r2){return tr[x];}
	down(x);
	I M=l+r>>1;
	if(r2<=M) return qry(L,l,M,l2,r2);
	else if(l2>M) return qry(R,M+1,r,l2,r2);
	else return max(qry(L,l,M,l2,M),qry(R,M+1,r,M+1,r2));
}
void ad(I x,I l,I r,I l2,I r2,ll val){
	if(l==l2&&r==r2){
		tr[x]+=val,lzy[x]+=val;
		return;
	}
	down(x);
	I M=l+r>>1;
	if(r2<=M) ad(L,l,M,l2,r2,val);
	else if(l2>M) ad(R,M+1,r,l2,r2,val);
	else{ad(L,l,M,l2,M,val),ad(R,M+1,r,M+1,r2,val);}
}
I main(){
	freopen("herbary.in","r",stdin);
	freopen("herbary.out","w",stdout);
	scanf("%d",&n);
	F(i,1,n){
		scanf("%d%lld%lld",&a[i],&v[i],&c[i]);
		h[i]=node{a[i],i};
	}
	sort(h+1,h+1+n,cmp);
	F(i,1,n){
		if(h[i].v!=h[i-1].v) cnt++;
		rk[h[i].id]=cnt;
	}
	memset(tr,-127,sizeof tr);
	cg(1,0,n,0,0);
	F(i,1,n){
		f[i]=v[i]+qry(1,0,n,0,rk[i]);
		cg(1,0,n,rk[i],f[i]);
		ad(1,0,n,0,rk[i]-1,-c[i]);
		f[i]=max(f[i],f[i-1]);
	}
	memset(tr,-127,sizeof tr);
	cg(1,0,n,0,0);
	Fd(i,n,1){
		g[i]=v[i]+qry(1,0,n,0,rk[i]);
		cg(1,0,n,rk[i],g[i]);
		ad(1,0,n,0,rk[i]-1,-c[i]);
		g[i]=max(g[i],g[i+1]);
	}
	F(i,1,n-1){ans=max(ans,f[i]+g[i+1]);}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/107639645