BZOJ1483: [HNOI2009]梦幻布丁

来源:互联网 发布:当今社会如何致富知乎 编辑:程序博客网 时间:2024/04/28 11:18

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

Output

针对第二类操作即询问,依次输出当前有多少段颜色.

Sample Input

4 3
1 2 2 1
2
1 2 1
2

Sample Output

3
1

HINT

Source

维护一个链表 启发式合并就好了
注意记录每个颜色的实际颜色
#include <bits/stdc++.h>using namespace std;const int maxn = 100010;const int maxm = 1000010;int a[maxn], nxt[maxn], head[maxm], tail[maxm], cnt[maxm], f[maxm], n, m, ans, mx;inline int read(){char ch = getchar();int tmp = 0;while( ch < '0' || ch > '9' ) ch = getchar();while( ch >= '0' && ch <= '9' ) tmp = tmp * 10 + ch - '0', ch = getchar();return tmp;}int main(){n = read(), m = read();for( int i = 1 ; i <= n ; i++ ){mx = max( mx, a[ i ] = read() );if( a[ i ] ^ a[ i - 1 ] ) ans++;if( !tail[ a[ i ] ] ) head[ a[ i ] ] = i;nxt[ i ] = tail[ a[ i ] ];tail[ a[ i ] ] = i;cnt[ a[ i ] ]++;}for( int i = 1 ; i <= mx ; i++ ) f[ i ] = i;while( m-- ){int opt = read();if( opt == 2 ) { printf( "%d\n", ans ); continue; }int x = read(),  y = read();if( f[ x ] == f[ y ] ) continue;if( cnt[ f[ x ] ] > cnt[ f[ y ] ] ) swap( f[ x ], f[ y ] );x = f[ x ], y = f[ y ];if( !cnt[ x ] ) continue;for( int i = tail[ x ] ; i ; i = nxt[ i ] ){if( a[ i - 1 ] == y ) ans--;if( a[ i + 1 ] == y ) ans--;}for( int i = tail[ x ] ; i ; i = nxt[ i ] ) a[ i ] = y;nxt[ head[ x ] ] = tail[ y ], tail[ y ] = tail[ x ], cnt[ y ] += cnt[ x ];cnt[ x ] = head[ x ] = tail[ x ] = 0;}return 0;}


0 0