1. 程式人生 > >bzoj 1483 夢幻補丁

bzoj 1483 夢幻補丁

while data sizeof pri des else display bzoj 例如

Description

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

Input

第一行給出N,M表示布丁的個數和好友的操作次數. 第二行N個數A1,A2...An表示第i個布丁的顏色從第三行起有M行, 對於每個操作, 若第一個數字是1表示要對顏色進行改變,其後的兩個整數X,Y表示將所有顏色為X的變為Y,X可能等於Y. 若第一個數字為2表示要進行詢問當前有多少段顏色,這時你應該輸出一個整數. 0。 n,m<=1000000

Output

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

Sample Input

4 3
1 2 2 1
2
1 2 1
2

Sample Output

3
1

HINT

思路: 本題可以啟發式合並,每次把數量少的顏色合並到數量大的顏色,這樣的話由於每次都要擴大一倍以上,所以每個數參與合並的次數不會超過logn,總的時間復雜度是nlogn。

先把初始序列的答案統計出來,然後把每種數都用一個鏈表串起來,修改的時候把兩種數的鏈表合並一下。修改答案的時候,比如把數x全部修改為數y,那麽把數x的鏈表遍歷一次,某個數x左邊有y就把答案-1,右邊有y也-1。

技術分享圖片
 1 #include<bits/stdc++.h>
 2 using namespace
std; 3 #define R register int 4 #define rep(i,a,b) for(R i=a;i<=b;i++) 5 #define Rep(i,a,b) for(R i=a;i>=b;i--) 6 #define LL long long 7 #define ms(i,a) memset(a,i,sizeof(a)) 8 #define lc (x<<1) 9 #define rc (x<<1|1) 10 #define mid (l+r)/2 11
#define gc() getchar() 12 template<class T>void read(T &x){ 13 x=0; char c=0; 14 while (!isdigit(c)) c=gc(); 15 while (isdigit(c)) x=x*10+(c^48),c=gc(); 16 } 17 int const N=1000000+3; 18 int n,m,a[N],ans,pos[N],size[N],f[N],nt[N],last[N]; 19 int main(){ 20 read(n); read(m); 21 rep(i,1,n){ 22 read(a[i]); 23 if(a[i]!=a[i-1]) ans++ ; 24 pos[a[i]]=a[i]; 25 if(!f[a[i]]) f[a[i]]=i; 26 size[a[i]]++; nt[i]=last[a[i]]; last[a[i]]=i; 27 } 28 rep(i,1,m){ 29 int k; 30 read(k); 31 if(k==1){ 32 int x,y; 33 read(x); read(y); 34 if(x==y) continue; 35 if(size[pos[x]]>size[pos[y]]) swap(pos[x],pos[y]); 36 x=pos[x];y=pos[y]; 37 if(!size[x]) continue; 38 for(int i=last[x];i;i=nt[i]){ 39 if(a[i+1]==y) ans--; 40 if(a[i-1]==y) ans--; 41 } 42 for(int i=last[x];i;i=nt[i]) a[i]=y; 43 size[y]+=size[x]; size[x]=0; 44 nt[f[y]]=last[x]; f[y]=f[x]; 45 }else printf("%d\n",ans); 46 } 47 return 0; 48 }
View Code

bzoj 1483 夢幻補丁