總結 二叉堆 7 20

2021-10-08 08:12:47 字數 3473 閱讀 5012

堆一般有兩個重要的操作,put(往堆中加入乙個元素)和get(從堆中取出並刪除乙個元素)。put一般用來建堆和維護堆,get則是得到最小值。

堆在noip競賽中應用廣泛,常用與快速查詢最大(最小值),優化各種演算法(如:最短路演算法、dp演算法),是一種效率高,應用廣泛的資料結構。

顯然,堆只能以乙個關鍵字作為順序,若乙個決策涉及時間和權值,那就必須轉換問題,使時間(或權值)的條件弱化,這樣就可以愉快地貪心了

下面以大根堆為例:

void

up(node x)

}

void

down()

}

題目描述

如題,初始小根堆為空,我們需要支援以下3種操作:

操作1: 1 x 表示將x插入到堆中

操作2: 2 輸出該小根堆內的最小數

操作3: 3 刪除該小根堆內的最小數

解析:板子題

#include

#include

#include

using

namespace std;

const

int maxn=

100005

;int n,a[maxn]

,heap[maxn]

,cnt=0;

voidup(

int p)

}void

down

(int p)

}int

main()

else

if(ok==2)

printf

("%d\n"

,heap[1]

);else

}}

解析:我們可以發現,假設能釣到魚的數量僅和已釣魚的次數有關,且每次釣魚的時間都是整數分鐘。則每次釣魚都要取當前最大值。但本題路程是變數,可以列舉到達的最遠魚塘,顯然不會走回頭路(因為與釣魚先後無關),我們可以加入[1,i]的魚塘,令t=m

−l[i

]t=m-l[i]

t=m−l[

i],其中l

ll表示路程所花費時間。每次從二叉堆中取出並刪除最大值,修改後再加入,重複t

tt次就得到了當前最大價值。

#include

#include

#include

using

namespace std;

const

int maxn=

105;

struct nodeheap[maxn]

,st,now;

int n,m,cnt,a[maxn]

,b[maxn]

,l[maxn]

,ans;

void

up(node x)

}node down()

return res;

}int

main()

scanf

("%d"

,&m)

;for

(int i=

1;i<=n;i++

)while

(t--

) ans=

max(ans,tot);}

printf

("%d"

,ans)

;}

二叉堆其實很擅長於求前m個大的決策,我們通常是先求最大,再求次大,以此推廣。或者先求區域性最優解,再縮小問題規模,直到問題解決。(貪心思想)

顯然可以有70pts的dp**:

#include

#include

#include

#define ll long long

using

namespace std;

const

int maxn =

100005

;ll n, k, a[maxn]

, f[maxn]

, dp[3]

[maxn]

;int

main()

for(

int i =

0; i <=

2; i++

) dp[i][0

]=0;

for(

int i =

2; i <= n; i++)}

printf

("%lld"

, dp[n %3]

[k])

;}

不難想到, 為了使佈線長度盡量小,每對佈線的辦公樓一定是相鄰的

所以我們可以在讀入時計算差分陣列儲存每相鄰兩個辦公樓的距離

這樣問題轉化為, 在差分陣列中找k個數,滿足k個數之和最小且互不相鄰

設差分陣列為b, 其中最小的數為b[i]

顯然最優解必定是一下其中一種

1.包含b[i]以及除b[i-1]和b[i+1]的數

2.包含b[i-1]和b[i+1]以及除b[i],b[i-2],b[i+2]

從這一點擴充套件, 可以先取b[i],並以b[i-1]+b[i+1]-b[i]替換,

然後在新數列中繼續重複k-1次得到最後結果

這樣若b[i]不屬於最優解,則b[i-1]+b[i+1]-b[i]必定被選,滿足了上述第二種情況

更具體做法是, 將原差分陣列每個值插入堆, 並將陣列以煉表串起來

每次取堆頂最小值更新答案,並刪除該值,

設最小值編號為i, 那麼再插入b[ pre[i] ]+b[ nxt[i] ]-b[i], 並更新鍊錶

重複k次即得最優解

#include

using

namespace std;

const

int maxn=

100005

;const

int inf=

0x3f3f3f3f

;void

read

(long

long

&x)while

(c>=

'0'&&c<=

'9')

x*=f;

}long

long n,k,m,ans,l[maxn]

,r[maxn]

,p[maxn]

;bool vis[maxn]

;priority_queuelong

long

,int

>

> q;

intmain()

for(

int i=

1;i<=m;i++

) p[0]

=p[n]

=inf;

//為什麼要這樣賦值?

for(

int i=

1;i<=k;i++

)printf

("%lld"

,ans)

;}

二叉堆學習總結

二叉堆是一種特殊的堆,二叉堆是完全二元樹 二叉樹 或者是近似完全二元樹 二叉樹 二叉堆有兩種 最大堆和最小堆。最大堆 父結點的鍵值總是 大於或等於 任何乙個子節點的鍵值。最小堆 父結點的鍵值總是 小於或等於 任何乙個子節點的鍵值。二叉堆用陣列儲存,從下標1開始,並且因為二叉堆為完全二叉樹,所以除根節...

(二叉)堆操作

堆操作 實驗目的 一 建堆 將陣列a 1.n 變成乙個最大堆。二 堆排序 將乙個堆中的元素按遞減排序輸出。三 用插入方法建堆 堆大小從1到n每次插入乙個元素到堆中,直到n個元素入堆。實驗原理 二叉 堆是乙個陣列,它可以被看成乙個近似的完全二叉樹。樹上的每乙個結點對應陣列中的乙個元素。除了最底層外,該...

簡單 二叉堆

堆是一種比較有用的資料結構,是二叉樹的一種陣列的表示形式。最大堆和最小堆是二叉堆的兩種形式。最大堆 根結點的鍵值是所有堆結點鍵值中最大者。最小堆 根結點的鍵值是所有堆結點鍵值中最小者。而最大 最小堆集結了最大堆和最小堆的優點,這也是其名字的由來。最大 最小堆是最大層和最小層交替出現的二叉樹,即最大層...