懶人的福利 教你用set維護斜率優化凸包

2022-05-02 02:15:13 字數 3195 閱讀 3703

斜率優化題目大家肯定都做得不少了,有一些題目查詢插入點的x座標和查詢斜率都不單調,這樣就需要維護動態凸包並二分斜率。(例如bzoj1492)

常規的做法是cdq分治或手寫平衡樹維護凸包,然而如果我不願意寫分治,也懶得打平衡樹,怎麼辦呢?

沒關係,今天我告訴你怎麼用乙個set維護這種凸包。

首先orzlh,沒什麼特殊意義,只是單純的orz。

我們定義f[i]表示在第i天能擁有的金券組數,按照第i天的比例。

那麼,我們要把前面的金券在今天賣出獲得最多的錢,並在今天進行**。

所以,f[i]=max((f[j]*a[i]+f[j]/rate[j]*b[i])/(a[i]+rate[i]*b[i]))。

除下去的東西是乙個常數,扔掉。

然後我們就有:

t=max(a[i]*(f[j])+b[i]*(f[j]/rate[j]))。

如果我們把f[j]看做x,f[j]/rate[j]看做y,我們有:

t=a*x+b*y,兩邊同時除以b,得到:

t/b=(a/b)x+y

y=(t/b)-(a/b)*x

好的,現在我們有一條斜率為-(a/b)的直線,要找乙個點使之截距最大。

這樣我們維護乙個右上1/4凸殼即可。

怎麼維護?

我們考慮不用斜率優化,單純水平序維護凸包,那麼點是按照x座標單增在平衡樹上排列的。

現在我們在每個點維護他與後面點連線斜率,我們會發現:這個斜率是單降的。

所以,我們可以通過適當地轉換cmp函式,來通過乙個set完成兩種比較。

我們定義:

1

int cmp; //

0 compare x , 1 compare slope .

2struct

point

8 friend point operator - (const point &a,const point &b) ;10}

11 friend double

operator * (const point &a,const point &b)

14 inline double calc(double a,double b) const

17};

18set

st;

插入就是正常凸包插入,最後再維護一下斜率就行了。注意彈出左邊後迭代器會失效,所以需要重新lower_bound一下。(可能原來你的迭代器是原來的end,結果彈出左邊後end改變了,兩個end不同,然後你去彈出右邊,訪問無效迭代器,就直接re了)

1 inline void pop_right(set

::iterator nxt,const point &p) 9}

10 inline void pop_left(set

::iterator prv,const point &p) 17}

18 inline void insert(const point &p)

31 nxt = lst , ++nxt;

32if(nxt!=st.end()) else

41 }

查詢的話就更改一下比較函式,然後特判一下邊界防止re就好。

1 inline double query(const

intid) ); //

it can't be st.end() if st isn't empty .

5if( it==st.end() ) return0;

6double ret = it->calc(a[id],b[id]);

7if( it !=st.begin() )

11return

ret;

12 }

所以整體**:

bzoj1492:

1 #include2 #include3 #include

4 #include5

using

namespace

std;

6const

int maxn=1e5+1e2;78

int cmp; //

0 compare x , 1 compare slope .

9struct

point

15 friend point operator - (const point &a,const point &b) ;17}

18 friend double

operator * (const point &a,const point &b)

21 inline double calc(double a,double b) const

24};

25set

st;26

double

a[maxn],b[maxn],rate[maxn],f[maxn],ans;

2728 inline void pop_right(set

::iterator nxt,const point &p) 36}

37 inline void pop_left(set

::iterator prv,const point &p) 44}

45 inline void insert(const point &p)

58 nxt = lst , ++nxt;

59if(nxt!=st.end()) else68}

69 inline double query(const

intid) ); //

it can't be st.end() if st isn't empty .

73if( it==st.end() ) return0;

74double ret = it->calc(a[id],b[id]);

75if( it !=st.begin() )

79return

ret;80}

8182

intmain() );90}

91 printf("

%0.3lf\n

",ans);

92return0;

93 }

view code

不得不說stl的set跑的還是挺快的。

這裡是回檔後的世界,無論你做什麼,你都一定會這樣做。

而我努力改變命運,只是為了防止那一切重現。

(來自某中二病晚期患者(不))

8 教你用 opencv 訓練屬於自己的模型

當前模型訓練將在win10系統下去完成,首先還是安裝好opencv,我這裡安裝在了 d opencv 目錄下。為了訓練自己的模型,首先我們需要將 d opencv build x64 vc15 bin 目錄下的 opencv createsamples.exe opencv traincascade...

教你用記事本做整人的另類簽名

教你用記事本做整人的另類簽名 2011年12月24日 今天來教大家怎麼製作這樣的簽名圖。很簡單的,只要運用vbs指令碼語言就行了.1.執行windows自帶的記事本,在裡面輸入以下內容 msgbox 對不起,您灌水太多需要重新啟動計算機。chr 10 確定要重啟嗎?33,重新啟動計算機 2.儲存文字...

教你用記事本做整人的另類簽名

教你用記事本做整人的另類簽名 2011年12月24日 今天來教大家怎麼製作這樣的簽名圖。很簡單的,只要運用vbs指令碼語言就行了.1.執行windows自帶的記事本,在裡面輸入以下內容 msgbox 對不起,您灌水太多需要重新啟動計算機。chr 10 確定要重啟嗎?33,重新啟動計算機 2.儲存文字...