HNOI2009 夢幻布丁 啟發式合併 佇列

2021-08-25 19:39:07 字數 1091 閱讀 3688

傳送門

題意:n個布丁擺成一行,進行m次操作.每次將某個顏色的布丁全部變成另一種顏色的,然後再詢問當前一共有多少段顏色。

題解:啟發式合併的神奇做法

把同種顏色的布丁排成一列,變色時接在那個顏色的佇列後面;同時要把短的佇列接在長的佇列後面。

複雜度證明:由於每個操作中,合併短的佇列和長的佇列,合併後的佇列至少有短的佇列的2倍長

最多擴大lo

gnl og

n次,複雜度o(

nlog

n)o (n

logn

)。

那麼問題來了:如果改變顏色時,原來顏色的佇列比改變顏色的佇列長怎麼辦呢?我們可以記錄乙個start陣列,表示這個顏色實際上處於哪一佇列。

#include

#include

#include

using

namespace

std;

const

int maxn = 100001;

int a[maxn], c[maxn];

int tail[1000001], start[1000001], size[1000001];

int fir[1000001], nxt[maxn];

inline

int read()

while(ch >= '0' && ch <= '9')

return k * f;

}int main()

while(m--)

x = start[x], y = start[y]; //x接y上

if(!size[x]) continue;

for(int i = fir[x]; i; i = nxt[i])

for(int i = fir[x]; i; i = nxt[i]) a[i] = y;

nxt[tail[x]] = fir[y]; fir[y] = fir[x]; size[y] += size[x];

tail[x] = size[x] = fir[x] = 0;

}else

}return

0;}

HNOI2009 夢幻布丁 啟發式鍊錶合併

因為啟發式合併,所以我們強制用長鏈代表短鏈,遍歷修改短鏈的所有節點 由於我們只儲存了位置之間是同色的關係形成的鏈條,這些鏈條無顏色特徵,所以我們把長鏈分配給新顏色 即一次swap操作,用fa x 記錄顏色x的在c陣列中儲存的真實顏色 其他部分就是水水細節啦。include include inclu...

HNOI2009 夢幻布丁(鍊錶 啟發式合併)

洛谷傳送門 開始乙個o n 2 思路,每次每句要改變顏色的點,改變完顏色後重新計算顏色的段數,顯然拉閘。然後呢。然後就不會了。看了別人部落格,才知道有個叫做啟發式合併的東西,就是把小的合併到大的上面,時間複雜度就將為了log級別,額,為啥呢?反正這樣就更快了。然後對於此題 我們先求出原序列的答案 每...

HNOI 2009 夢幻布丁 鍊錶 啟發式合併

題意 給出乙個序列,每個元素有顏色。共m次操作,改變一種顏色或統計顏色的塊數 由於m,n都比較大,所以我們直接mn暴力是不行的,要考慮優化。那麼mn慢在 呢?每次操作時,都要遍歷一遍整個序列,其中訪問到了很多沒用的元素。那麼就從這裡入手,如果我們每次只遍歷要修改的元素,就能快很多。所以我們用鍊錶,把...