1. 程式人生 > 實用技巧 >有趣的有趣的家庭菜園——線段樹優化dp

有趣的有趣的家庭菜園——線段樹優化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
226030
464030
3610050
11140120
3812020
249060
535020

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 }