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

2022-03-01 12:18:13 字數 1342 閱讀 5736

洛谷傳送門

開始乙個o(n^2)思路,每次每句要改變顏色的點,改變完顏色後重新計算顏色的段數,顯然拉閘。

然後呢。。然後就不會了。

看了別人部落格,才知道有個叫做啟發式合併的東西,就是把小的合併到大的上面,時間複雜度就將為了log級別,額,為啥呢?

反正這樣就更快了。

然後對於此題

我們先求出原序列的答案

每一種顏色搞一條鏈把該色結點串起來,記錄下鏈條尾結點

把一種顏色的染成另一種,很簡單把它合併過去,然後處理下對於答案的影響

但是。。。

比如把1染成2,但是s[1]>s[2],這時我們應該將2合併到1的鏈後面,但是會遇到乙個麻煩的問題,就是這個鏈頭是接1下的,也就是說以後找顏色2,發現沒有顏色2只有顏色1。。。

於是我們應該開乙個陣列f,表示我們尋找一種顏色時,實際應該找哪個顏色下的鏈,遇到上面那種情況要交換f[1]和f[2]

1 #include 2 #include 3

#define maxn 10000545

using

namespace

std;67

intn, m, maxx, ans;

8int a[maxn], next[maxn], head[maxn * 10], tail[maxn * 10], cnt[maxn * 10], f[maxn * 10];9

10int

main()

1124

for(i = 1; i <= m; i++)

2539

for(j = tail[x]; j; j = next[j]) a[j] =y;

40 next[head[x]] = tail[y];//

把 x 合併到 y 上

41 tail[y] =tail[x];

42 cnt[y] +=cnt[x];

43 head[x] = tail[x] = cnt[x] = 0;44

}45else printf("

%d\n

", ans);46}

47return0;

48 }

view code

把 x 插到 y 的後面,所以得寫成

next[head[x]] =tail[y]; 

tail[y] = tail[x];

也可以把 x 插到 y 的前面,寫成

next[head[y]] =tail[x];

head[y] = head[x]

HNOI2009 夢幻布丁

題意 n個布丁擺成一行,進行m次操作.每次將某個顏色的布丁全部變成另一種顏色的,然後再詢問當前一共有多少段顏色.例如顏色分別為1,2,2,1的四個布丁一共有3段顏色.對每個顏色的位置維護鍊錶。合併兩個顏色,連線鍊錶,統計貢獻。統計貢獻的複雜度是與鍊錶長度有關的。如果遍歷長度短的鍊錶那麼複雜度自然更小...

HNOI2009 夢幻布丁

n個布丁擺成一行,進行m次操作.每次將某個顏色的布丁全部變成另一種顏色的,然後再詢問當前一共有多少段顏色.例如顏色分別為1,2,2,1的四個布丁一共有3段顏色.輸入格式 第一行給出n,m表示布丁的個數和好友的操作次數.第二行n個數a1,a2.an表示第i個布丁的顏色從第三行起有m行,對於每個操作,若...

HNOI2009 夢幻布丁

題目鏈結 把每一種數字想象成乙個佇列。如果暴力合併,時間複雜度必然很高,考慮啟發式合併 每次把數字少的佇列合併到數字多的佇列上去。每次合併,若數字少的佇列數字個數為 s 則合併之後產生新佇列的大小必定不小於 2 s 時間複雜度 o n log n 這樣合併產生了乙個問題 即原來要求將 a 全部變為 ...