有趣的有趣的家庭菜園——線段樹優化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草。
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 }