有趣的有趣的家庭菜園 線段樹優化dp

2022-08-18 23:00:25 字數 3969 閱讀 2090

職業經營家庭菜園的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君能獲得的最大利益

722 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 #include2 #include3 #include4 #include5 #include6 #include7 #include8

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()

17while(isdigit(c))

18return a*b;19}

20const

int n=2e5+50,m=6e6+50,inf=123456789012345;21

struct

nodet[m],t[m];

24int n,q,b[n],h[n],p[n],c[n],f[n][2],ans=-inf;

25void spread(int

p)33

return;34

}35void pushup(int

p)38

void putin(int p,int l,int r,int k,int

z)43

spread(p);

44if(k<=mid)putin(lp,l,mid,k,z);

45else putin(rp,mid+1

,r,k,z);

46pushup(p);47}

48void add(int p,int l,int r,int l,int r,int

z)54

spread(p);

55if(r<=mid)add(lp,l,mid,l,r,z);

56else

if(l>mid)add(rp,mid+1

,r,l,r,z);

57else add(lp,l,mid,l,mid,z),add(rp,mid+1,r,mid+1

,r,z);

58pushup(p);59}

60int query(int p,int l,int r,int l,int

r)64

spread(p);

65if(r<=mid)return

query(lp,l,mid,l,r);

66else

if(l>mid)return query(rp,mid+1

,r,l,r);

67else

return max(query(lp,l,mid,l,mid),query(rp,mid+1,r,mid+1

,r));68}

6970

71void spread1(int

p)79

void pushup1(int

p)82

void putin1(int p,int l,int r,int k,int

z)87

spread1(p);

88if(k<=mid)putin1(lp,l,mid,k,z);

89else putin1(rp,mid+1

,r,k,z);

90pushup1(p);91}

92void add1(int p,int l,int r,int l,int r,int

z)98

spread1(p);

99if(r<=mid)add1(lp,l,mid,l,r,z);

100else

if(l>mid)add1(rp,mid+1

,r,l,r,z);

101else add1(lp,l,mid,l,mid,z),add1(rp,mid+1,r,mid+1

,r,z);

102pushup1(p);

103}

104int query1(int p,int l,int r,int l,int

r)108

spread1(p);

109if(r<=mid)return

query1(lp,l,mid,l,r);

110else

if(l>mid)return query1(rp,mid+1

,r,l,r);

111else

return max(query1(lp,l,mid,l,mid),query1(rp,mid+1,r,mid+1

,r));

112}

113signed main()

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++)

126for(int i=1;i<=n;i++)

131for(int i=n;i>=1;i--)

136for(int i=1;i<=n;i++)ans=max(ans,f[i][1]+f[i][0]-p[i]);

137 printf("

%lld\n

",ans);

138return0;

139 }

有趣的家庭菜園

對家庭菜園有興趣的joi君每年在自家的田地中種植一種叫做ioi草的植物。joi君的田地沿東西方向被劃分為n個區域,由西到東標號為1 n。ioi草一共有n株,每個區域種植著一株。在第i個區域種植的ioi草,在春天的時候高度會生長至hi,此後便不再生長。為了觀察春天的樣子而出行的joi君注意到了ioi草...

ssoj2455有趣的有趣的家庭菜園(線段樹)

題意 有乙個n塊的線性菜園,每塊菜園只有照到陽光 左右兩邊沒有遮擋 才能收穫果實賣出去價值為p,也可以除去費用為c,問最大利益是多少 思路 列舉n塊田地i為最高處,ans即為其左邊最大利潤加右邊最大利潤。dp o n 2 會超時。用線段樹維護左邊 右邊 最大值,點更新,與區間值的更改。include...

JOI 有趣的有趣的家庭菜園Fgarden

職業經營家庭菜園的joi君每年在自家的田地中種植一種叫做ioi草的植物。ioi草的種子在冬天被播下,春天會發芽並生長至乙個固定的高度。到了秋天,一些ioi草會結出美麗的果實,並被收穫,其他的ioi草則會在冬天枯萎。joi君的田地沿東西方向被劃分為n個區域,從西側開始的第i個區域中種植著ioi草i。在...