Noip模擬考第三題 飢餓遊戲

2022-06-01 10:12:10 字數 3241 閱讀 1756

飢餓遊戲

(hungry.pas/c/cpp)

【問題描述】

chanxer餓了,但是囊中羞澀,於是他去參加號稱免費吃到飽的「飢餓遊戲」。

這個遊戲的規則是這樣的,舉辦者會擺出一排 個食物,希望你能夠一口就吃完。

然而chanxer卻不這麼想,比起數量,他更看重質量,對於沒乙個食物,都會有乙個喜愛值,chanxer希望能夠吃到最美味的那一段。

注意,因為只能吃一口,因此chanxer只有一次機會,即只能吃連續的一段,因為他的嘴夠大,因此無論這一段有多長,他都可以吃到。

不過chanxer是乙個喜新厭舊的男人,對於多個喜愛值相同的食物,他會只算作一次,比如: ,2出現了3次,但只算一次,於是這一段的喜愛值是 。

現在chanxer對於吃哪一段有很多想法,每乙個想法他都想要試試,但是由於只有一次機會,所以他想要你先幫他算算這些他想要吃的段帶給他的喜愛值是多少。

【輸入】

輸入檔名為hungry.in,共 行。

第一行包含乙個整數 n。

接下來一行,n個整數,第i個數表示第i個食物的喜愛值a。

接下來一行包含乙個整數 m ,表示chanxer的詢問個數。

接下來 m行,每行兩個數 l,r,表示chanxer要詢問這個區間的喜愛值【注意是指這個區間內的最優值】。

【輸出】

輸出檔名為hungry.out,共m行。

每行乙個整數表示此次詢問的答案。

【輸入輸出樣例】

hungry.in

hungry.out

94 -2 -2 3 -1 -4 2 2 -6

31 2

1 54 945

3【資料說明】

對於 的資料滿足,n,m<=100;

對於 的資料滿足, n,m<=100,000,|ai|<=100,000。

【分析】這題當場最高30分....結果還沒有solution ! 無奈只能orz std的**了... 然而std的**高能——使用zkw線段樹....

多虧我當初還是看過一些zkw線段樹...於是拉上zero去黑板上進行模擬運算....畫了兩棵巨大的線段樹...終於半猜半模擬的弄懂了std的思路,爽啊!

正解的具體思路:

1.發現每次詢問[l,r]中的最優值,無非是另乙個直接取的乙個小的區間 [l,r]滿足 l>=l && r<=r。

2.因為相同的數在一段區間內只會加一次,所以每次在兩個相鄰的相同的數之間加入這個數。

【經過這兩個比較核心的思路】

std設計了乙個線段樹來每次獲得最優值。

每次移動右端點,每次將右端點的值新增進線段樹更新一段區間[pre[i]+1,i]的最優值。

其中每個葉子節點帶有兩個屬性:g[i],f[i]

g[i]表示從i到當前列舉的最右端點能獲得的最優值[但是要求必須選擇i這個節點作為左端點],右端點是不固定的。

f[i]表示從i到當前列舉的最右端點的總和[要求左端點為i,右端點為當前列舉的最右端點],左右端點都是固定的。

所以可以想到g[i]每次都是由f[i]更新的。

但是每次這樣傳到每個葉節點太慢了,於是利用線段樹的方法,每次給一段區間新增乙個值時,使用lazy_tag,也就是說每個非葉節點多了兩個屬性: gd[i],fd[i]

而每個非葉節點還表示這個區間內元素,所以它們也具有乙個g,f的意義

g[i]表示以i能控制的區間內的任意元素作為左端點到當前列舉右端點能獲得的最優值 [即i控制區間內g的最優值]

f[i]表示以i能控制的區間內的任意元素作為左端點,當前列舉右端點作為區間右端點能獲得的最優值 [即i控制區間內f的最優值]

gd[i]表示對於i能控制的區間內曾經可以新增的最多的值 [也就是沒來得及下傳的最好的一次 tag]

fd[i]表示對於i控制的區間內到現在為止累積的值 [也就是每次累加得到的值而已]

所以也可以想到gd[i]是由fd[i]更新的。

可以發現每次再新增tag的時候需要下傳一些 tag,和線段樹一樣。

下傳的時候更新下面節點的tag,gd由gd[fa]+fd更新,fd變成fd[fa]+fd

下傳時還要更新下面節點的g和f,其中g由gd[fa]+f更新,f變成fd[fa]+f

現在每個答案就比較好求了,因為代表的意義有當前右端點存在的影響,需要離線處理,將詢問按右端點排序,然後列舉右端點,如果右端點與某個r重合,查詢[l,r]內的最優g即可。

1 #include2 #include3 #include4

5using

namespace

std;

67 typedef long

long

ll;8

const

int nmax=100000,tmax=1

<<18,shift=nmax;910

intn,m;

11int m=1,h=1;12

int a[nmax+18],last[nmax*2+18],pre[nmax+18

];13 ll f[tmax+18],g[tmax+18],fd[tmax+18],gd[tmax+18],ans[nmax+18

];14

int l[nmax+18],r[nmax+18],p[nmax+18

];15

16bool cmp(int i,int

j)19

20 inline int max(int a,int b)

2122 inline void update(ll &a,ll b)

2324 inline void take(int

i)27

28 inline void give(int i,int

j)34

35void pd(int

i)40

41void add(int l,int r,int

x)54

for(int tmp1,tmp2;l>>=1;)59}

6061 ll getmax(int l,int

r)68

return

ans;69}

7071

intmain()

view code

orz 人類智慧型的偉大...+資料結構的巧妙結合...

三向城(NOIP模擬題)

標籤 樹,lca 題目描述 三向城是乙個巨大的城市,之所以叫這個名字,是因為城市中遍布著數不盡的三岔路口。來自取名力為0的出題人 具體來說,城中有無窮多個路口,每個路口有唯一的乙個正整數標號。除了1號路口外,每個路口都連出正好3條道路通向另外3個路口 編號為x x 1 的路口連出3條道路通向編號為x...

2020 03 11模擬賽15(第三題)

題目描述 你是一名記者,現在要求你去採訪n 個國家的領導人。採訪每乙個國家的領導人需要消耗你的時間為t i 但你可以收穫價值為v i 的資訊,然後就能寫成報道 然而尷尬的是,有一些國家之間的關係屬於敵對關係,因此如果乙個國家的領導人知道你採訪了他的敵對國家領導人,那麼他就會拒絕你的採訪。總之,你採訪...

NOIP 2008提高組第三題

題名 傳紙條 可能是我太弱了一開始複雜度計算錯了 結果花10min打了個暴力才30分 然後才開始想dp正解 首先紙條正反傳一次的問題可以轉化為正著滿足條件的傳2次 然後我們考慮乙個狀態 f i j k l i,j,k,l 表示正著第一次傳到 i,j 第二次傳到 k,l 時最優解為f i j k l ...