傳送門
題意: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慢在 呢?每次操作時,都要遍歷一遍整個序列,其中訪問到了很多沒用的元素。那麼就從這裡入手,如果我們每次只遍歷要修改的元素,就能快很多。所以我們用鍊錶,把...