1. 程式人生 > >[bzoj1483][HNOI2009]夢幻布丁

[bzoj1483][HNOI2009]夢幻布丁

1483: [HNOI2009]夢幻布丁

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 4092  Solved: 1674
[ Submit][ Status][ Discuss]

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

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

 

題解:

     注意到:顏色一定是單調不增,段數一定是單調不增的,可以一邊修改一邊ans--;

          用連結串列維護每一個顏色的下標,啟發式合併,每次取出較小的,如果某個位置的前面或後面原來不同改顏色後相同了就ans--;

          實現注意細節;

        

 1 #include<bits/stdc++.h>
 2 #define il inline 
 3 #define rg register 
 4 using namespace std;
 5 const int N=1000010;
 6 int n,m,hd[N],nt[N],ans,a[N],id[N],sz[N];
 7 il void adde(int x,int y){nt[y]=hd[x];hd[x]=y;sz[x]++;}
 8 void solve(int x,int y){
 9     for(int i=hd[x];i;i=nt[i]){
10 if(a[i-1]==y)ans--; 11 if(a[i+1]==y)ans--; 12 } 13 for(int i=hd[x];i;){ 14 int tmp=i; i=nt[i]; 15 adde(y,tmp); 16 a[tmp]=y; 17 } 18 hd[x]=0; 19 } 20 int main(){ 21 // freopen("bzoj1483.in","r",stdin); 22 // freopen("bzoj1483.out","w",stdout); 23 scanf("%d%d",&n,&m); 24 for(int i=1;i<=1e6;i++)id[i]=i; 25 for(rg int i=1;i<=n;i++){ 26 scanf("%d",&a[i]); 27 adde(a[i],i); 28 if(a[i]!=a[i-1])ans++; 29 } 30 for(int i=1,op,x,y;i<=m;i++){ 31 scanf("%d",&op); 32 if(op&1){ 33 scanf("%d%d",&x,&y); 34 if(x==y)continue; 35 if(sz[x]>sz[y]){ 36 solve(id[y],id[x]); 37 swap(id[y],id[x]); 38 }else solve(id[x],id[y]); 39 }else printf("%d\n",ans); 40 } 41 return 0; 42 } 43
bzoj1483