有趣的有趣的家庭菜园——线段树优化dp
有趣的有趣的家庭菜园
职业经营家庭菜园的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草中获取的最大利益到底有多少呢?
第一行一个正整数N,表示田地被分为了N个区域。
接下来N行,第i行(1<=i<=N)三个空白分割的正整数Hi,Pi,Ci,表示第i株IOI草在春天时高度会生长至Hi,秋天收获的果实的价格为Pi,拔除所需费用为Ci。
输出一行一个整数,表示JOI君能获得的最大利益
7
22 60 30
46 40 30
36 100 50
11 140 120
38 120 20
24 90 60
53 50 20
320
【HINT】
拔除IOI草2和IOI草7,剩余的IOI草如下图所示:
IOI草1、3、5、6的果实价格分别为60、100、120、90,拔除IOI草2和IOI草7的花销分别为30、20,总收益为320,这是所有方案中的最大值。
对于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)
分析:
其实也不算分析啦,就反思一下改了那么久bug的原因。首先,我自己感觉出了一种神奇的线段树维护方法,然后似乎被数据证明是错的。接着求助了mlg,发现自己以为的很蠢的地方出错了。。。脸好疼,最后是维护是顺序调错了(其实是一开始的思路影响的)。唉,不说了不说了。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<queue> 6 #include<algorithm> 7 #include<vector> 8 using namespace std; 9 #define debug printf("zjyvegetable\n") 10 #define int long long 11 #define mid ((l+r)>>1) 12 #define lp (p<<1) 13 #define rp (p<<1|1) 14 inline int read(){ 15 int a=0,b=1;char c=getchar(); 16 while(!isdigit(c)){if(c=='-')b=-1;c=getchar();} 17 while(isdigit(c)){a=a*10+c-'0';c=getchar();} 18 return a*b; 19 } 20 const int N=2e5+50,M=6e6+50,inf=123456789012345; 21 struct node{ 22 int maxn,lazy; 23 }t[M],T[M]; 24 int n,q,b[N],h[N],p[N],c[N],f[N][2],ans=-inf; 25 void spread(int p){ 26 if(t[p].lazy){ 27 t[lp].maxn+=t[p].lazy; 28 t[rp].maxn+=t[p].lazy; 29 t[lp].lazy+=t[p].lazy; 30 t[rp].lazy+=t[p].lazy; 31 t[p].lazy=0; 32 } 33 return; 34 } 35 void pushup(int p){ 36 t[p].maxn=max(t[lp].maxn,t[rp].maxn); 37 } 38 void putin(int p,int l,int r,int k,int z){ 39 if(l==r){ 40 if(z>t[p].maxn)t[p].maxn=z; 41 return; 42 } 43 spread(p); 44 if(k<=mid)putin(lp,l,mid,k,z); 45 else putin(rp,mid+1,r,k,z); 46 pushup(p); 47 } 48 void add(int p,int l,int r,int L,int R,int z){ 49 if(l==L&&r==R){ 50 t[p].maxn+=z; 51 t[p].lazy+=z; 52 return; 53 } 54 spread(p); 55 if(R<=mid)add(lp,l,mid,L,R,z); 56 else if(L>mid)add(rp,mid+1,r,L,R,z); 57 else add(lp,l,mid,L,mid,z),add(rp,mid+1,r,mid+1,R,z); 58 pushup(p); 59 } 60 int query(int p,int l,int r,int L,int R){ 61 if(l==L&&r==R){ 62 return t[p].maxn; 63 } 64 spread(p); 65 if(R<=mid)return query(lp,l,mid,L,R); 66 else if(L>mid)return query(rp,mid+1,r,L,R); 67 else return max(query(lp,l,mid,L,mid),query(rp,mid+1,r,mid+1,R)); 68 } 69 70 71 void spread1(int p){ 72 T[lp].maxn+=T[p].lazy; 73 T[rp].maxn+=T[p].lazy; 74 T[lp].lazy+=T[p].lazy; 75 T[rp].lazy+=T[p].lazy; 76 T[p].lazy=0; 77 return; 78 } 79 void pushup1(int p){ 80 T[p].maxn=max(T[lp].maxn,T[rp].maxn); 81 } 82 void putin1(int p,int l,int r,int k,int z){ 83 if(l==r){ 84 if(z>T[p].maxn)T[p].maxn=z; 85 return; 86 } 87 spread1(p); 88 if(k<=mid)putin1(lp,l,mid,k,z); 89 else putin1(rp,mid+1,r,k,z); 90 pushup1(p); 91 } 92 void add1(int p,int l,int r,int L,int R,int z){ 93 if(l==L&&r==R){ 94 T[p].maxn+=z; 95 T[p].lazy+=z; 96 return; 97 } 98 spread1(p); 99 if(R<=mid)add1(lp,l,mid,L,R,z); 100 else if(L>mid)add1(rp,mid+1,r,L,R,z); 101 else add1(lp,l,mid,L,mid,z),add1(rp,mid+1,r,mid+1,R,z); 102 pushup1(p); 103 } 104 int query1(int p,int l,int r,int L,int R){ 105 if(l==L&&r==R){ 106 return T[p].maxn; 107 } 108 spread1(p); 109 if(R<=mid)return query1(lp,l,mid,L,R); 110 else if(L>mid)return query1(rp,mid+1,r,L,R); 111 else return max(query1(lp,l,mid,L,mid),query1(rp,mid+1,r,mid+1,R)); 112 } 113 signed main(){ 114 //freopen("herbary.in","r",stdin); 115 //freopen("herbary.out","w",stdout); 116 n=read(); 117 for(int i=1;i<=n;i++){ 118 b[i]=h[i]=read();p[i]=read(); 119 c[i]=read(); 120 } 121 sort(b+1,b+n+1); 122 q=unique(b+1,b+n+1)-b-1; 123 for(int i=1;i<=n;i++){ 124 h[i]=lower_bound(b+1,b+q+1,h[i])-b; 125 } 126 for(int i=1;i<=n;i++){ 127 f[i][0]=query(1,1,q,1,h[i])+p[i]; 128 if(h[i])add(1,1,q,1,h[i],-c[i]);//按公式来,先减再插 129 putin(1,1,q,h[i],f[i][0]); 130 } 131 for(int i=n;i>=1;i--){ 132 f[i][1]=query1(1,1,q,1,h[i])+p[i]; 133 if(h[i])add1(1,1,q,1,h[i],-c[i]); 134 putin1(1,1,q,h[i],f[i][1]); 135 } 136 for(int i=1;i<=n;i++)ans=max(ans,f[i][1]+f[i][0]-p[i]); 137 printf("%lld\n",ans); 138 return 0; 139 }