bzoj 1483 梦幻补丁

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

猜你喜欢

转载自www.cnblogs.com/ZJXXCN/p/10371929.html