有趣的有趣的家庭菜园——线段树优化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 }

 

posted @ 2020-07-28 22:15  zjy1412  阅读(121)  评论(0编辑  收藏  举报