bzoj 1455 羅馬遊戲 左偏樹入門

2021-09-30 13:54:12 字數 1275 閱讀 2223

左偏樹第一題,紀念一下

大概講一下左偏樹吧。。

首先它是乙個可以合併的堆,因此是可並堆的一種

什麼叫可以合併呢

就是說現在給你兩個堆,我現在要你將他們合併起來,變成乙個新的堆

要是一般的寫法我們是要講所有數拿出來,再重新插進去

但很顯然這樣的時間是過不去的。。

於是就有了這個東西

至於可並堆別的實現方法,(⊙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...