左偏樹:
左偏樹(leftist tree)是一種可並堆的實現。左偏樹是一棵二叉樹,它的節點除了和二叉樹的節點一樣具有鍵值外,還有乙個屬性距離(dist)。
距離指的是這個點到某個葉子結點的最短距離
[性質1]節點的左子節點的距離不小於右子節點的距離。
[性質2] 節點的距離等於它的右子節點的距離加1。(顯然)
——sd_le
優點:支援堆的logn合併,還可以打標記。
1.模板:
int mer(int x,inty)void pop(int
x)
所有的操作,都是在mer的支援下進行的。
複雜度證明:
因為每次都是對右子樹進行合併,不斷走右子樹,由於左子樹的距離大於等於右子樹的距離,所以複雜度logn
例題:2.bzoj 2809: [apio2012]dispatching
n個點組成一棵樹,每個點都有乙個領導力和費用,可以讓乙個點當領導,然後在這個點的子樹中選擇一些費用之和不超過m的點,得到領導的領導力乘選擇的點的個數(領導可不被選擇)的利潤。求利潤最大值。
n≤100000 ;
從葉子節點開始,每個點開始是乙個大根堆,堆裡的就是這個點的人。
往父親那裡合併堆,記錄堆的大小,費用的總和。
從兒子合併完畢後,在每個節點,不斷踢出費用最大的人,直到費用的總和<=m 這就是這個點的最優方案了。(顯然,花費最小的都留下了)
對於每個點,用這個點的領導力乘堆的大小嘗試更新答案即可。
注意:和子樹合併的時候,rt[x]=mer(rt[x],rt[y]) 注意是rt[y]因為這才是y的所屬堆的入口。
**:
#includeusingnamespace
std;
typedef
long
long
ll;const
int n=100000+10
;int
n;ll m;
ll c[n],p[n];
intrt[n];
ll siz[n];
ll ans;
struct
nodee[
2*n];
inthd[n],cnt;
void add(int x,int
y)struct
trz[n];
void pushup(int
x)int mer(int x,int
y)int split(int
x)void dfs(int x,int
fa)
while(z[rt[x]].sum>m&&z[rt[x]].siz)
ans=max(ans,z[rt[x]].siz*p[x]);
}int
main()
dfs(
1,0);
printf(
"%lld
",ans);
return0;
}
當要用到合併,打標記的堆的時候,就可以考慮左偏樹。
資料結構 可合併堆 左偏樹
剛剛又看了一遍左偏樹的內容,為了加深理解,自己也寫一篇,夾雜著許許多多的借鑑。左偏樹是可合併的二叉堆,首先滿足所有的堆的性質,其外,它還可以合併。左偏樹的樹節點需要儲存的資訊有 1.左右子樹節點編號 2.此節點到有空子結點的結點的最短距離 len 3.自身權值 首先解釋一下什麼是有空子節點的節點,就...
堆之左偏樹
左偏樹 左偏堆 優勢 兩個左偏樹合併效率高o logn 外結點 乙個結點的孩子數不滿兩個,就稱之為外結點。距離 dist 每個節點上有個距離 dist 的屬性,dist的值為該結點到最近的外結點所經過的邊的個數。外結點的dist 0。空結點的dist 1。左偏樹定義 1.是一顆二叉樹。2.是個堆。3...
左偏樹(可並堆)
左偏樹其實是一種可並堆,它可以 o log2 n o l og2n 合併兩個堆。那左偏?也就是說他左邊肯定有什麼東西比右邊大 別著急,在左偏樹上有乙個叫距離的東西 個點的距離,被定義為它子樹中離他最近的外節點到這個節點的距離 這與樹的深度不同 其中我們定義乙個節點為外節點,當且僅當這個節點的左子樹和...