左偏樹第一題,紀念一下
大概講一下左偏樹吧。。
首先它是乙個可以合併的堆,因此是可並堆的一種
什麼叫可以合併呢
就是說現在給你兩個堆,我現在要你將他們合併起來,變成乙個新的堆
要是一般的寫法我們是要講所有數拿出來,再重新插進去
但很顯然這樣的時間是過不去的。。
於是就有了這個東西
至於可並堆別的實現方法,(⊙v⊙)嗯,還不會。。
至於為什麼叫左偏樹呢,就是因為他左偏的性質
左偏啊,就是說左邊的「值」大
這裡的「值」是什麼呢,我們規定:
節點i稱為外節點(external node),當且僅當節點i的左子樹或右子樹為空 ( left(i) = null或right(i) = null );節點i的距離(dist(i))是節點i到它的後代中,最近的外節點所經過的邊數。特別的,如果節點i本身是外節點,則它的距離為0而左偏的性質就是
節點的左子節點的距離不小於右子節點的距離。可以證明:這樣下來一棵n個節點的左偏樹距離最多為log(n+1) -1
因為這樣的話最差情況就是一顆滿二叉樹嘛
這就是左偏樹時間複雜度的保證
接著我們合併的時候可能會使左偏樹變為一顆右偏樹,那麼我們只需要將他們的左右兒子交換就可以了。。
至於怎麼搞,大家可以看看**,接著自己弄幾個栗子模擬一下,我這裡就不給圖了
要是實在想看的朋友,看一去看05年黃源河的**
#include
#include
#define swap(x,y)
const
int n=1000005;
int n,m;
int v[n];
bool del[n];//這個點還存不存在
int f[n];
int d[n];//這個節點到外節點的最短距離
int l[n],r[n];//左右節點
int find (int x)
int merge (int x,int y)
int main()
else
int tx=find(a);del[tx]=true;
printf("%d\n",v[tx]);
f[tx]=merge(l[tx],r[tx]);
f[f[tx]]=f[tx];}}
return
0;}
BZOJ1455 羅馬遊戲 左偏樹
題解 本題顯然可以用堆來實現,維護乙個大根堆 但是無法進行合併操作,於是我們想到左偏樹。定義乙個結點的斜深度為這個節點不斷向自己的右兒子走 直到為葉子節點的長度。左偏樹的 左偏 指左兒子的斜深度一定大於等於右兒子的斜深度。合併就簡單了,我們可以歸併的來維護乙個左偏樹,設需合併的兩個樹的根節點為 k1...
bzoj1455 羅馬遊戲 左偏樹
time limit 5 sec memory limit 64 mb submit status discuss 第一行乙個整數n 1 n 1000000 n表示士兵數,m表示總命令數。第二行n個整數,其中第i個數表示編號為i的士兵的分數。分數都是 0.10000 之間的整數 第三行乙個整數m 1...
BZOJ 1455 羅馬遊戲 左偏樹
題目大意 給定n個點,每乙個點有乙個權值,提供兩種操作 1.將兩個點所在集合合併 2.將乙個點所在集合的最小的點刪除並輸出權值 非常裸的可並堆 n 100w 啟示式合併不用想了 左偏樹就是快啊 include include include include define m 1001001 usin...