HNOI2009 夢幻布丁

2022-05-12 12:01:23 字數 1614 閱讀 4457

n個布丁擺成一行,進行m次操作.每次將某個顏色的布丁全部變成另一種顏色的,然後再詢問當前一共有多少段顏色.例如顏色分別為1,2,2,1的四個布丁一共有3段顏色.

輸入格式: 

第一行給出n,m表示布丁的個數和好友的操作次數. 第二行n個數a1,a2...an表示第i個布丁的顏色從第三行起有m行,對於每個操作,若第乙個數字是1表示要對顏色進行改變,其後的兩個整數x,y表示將所有顏色為x的變為y,x可能等於y. 若第乙個數字為2表示要進行詢問當前有多少段顏色,這時你應該輸出乙個整數. 0

輸出格式:

針對第二類操作即詢問,依次輸出當前有多少段顏色.

輸入樣例#1:

4 3

1 2 2 1

21 2 1

2

輸出樣例#1:

3

1

1<=n,m<=100,000; 0題解:

用鍊錶+啟發式合併

1:將兩個佇列合併,有若干佇列,總長度為n,直接合併,最壞o(n),

2:啟發式合併呢?

每次我們把短的合併到長的上面去,o(短的長度)

咋看之下沒有多大區別,

下面讓我們看看均攤的情況:

1:每次o(n)

2:每次合併後,佇列長度一定大於等於原來短的長度的兩倍。

這樣相當於每次合併都會讓短的長度擴大一倍以上,

最多擴大logn次,所以總複雜度o(nlogn),每次o(logn)。

這題很容易搞混,啟發式合併可以這麼想,把x換成y可以視為把y換成x,在當前不會對答案有影響

但之後就會換錯顏色,所以從把x換成y變為把y換成x之後還要記下當前顏色的實際顏色(啟發式合併做了交換)

1 #include2 #include3 #include4 #include5

using

namespace

std;

6int nxt[1000001],head[1000001],color[1000001],set[1000001],size[1000001],ans,first[1000001

],n,m;

7void solve(int x,int

y)8

14for (i=head[x];i;i=nxt[i])

1518 nxt[first[x]]=head[y];

19 head[y]=head[x];

20 size[y]+=size[x];

21 head[x]=size[x]=first[x]=0;22

}23intmain()

24

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

3748

else

4952

}53 }

HNOI2009 夢幻布丁

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

HNOI2009 夢幻布丁

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

HNOI2009 夢幻布丁 線段樹合併

一開始是在splay專題下找的這道題,但是一想,好像更貼近線段樹的區間連續問題,然後就想著先去用線段樹去寫這道題,聽聞會出現顏色會超出1e7的範疇,所以,我就不考慮用陣列去開了,直接寫了map 的來解決這個問題。利用線段樹合併,對於已有的每個顏色來看,我們可以去知道最開始的情況,可以直接求得,然後就...