把每个颜色的下标存到set里。
考虑合并两个颜色,每次把size小的颜色合并到size大的颜色。
但是考虑下面这情况,比如现在要把1刷成2,但是1的size比2的size大,这时我们仍把2合并到1,那么以后对颜色2的操作,我们就要对颜色1进行了。
所以我们开一个数组fa[u],存的是颜色u实际对应的颜色。
/* Telekinetic Forest Guard */
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
typedef set<int>::iterator sit;
const int maxn = 100005, maxc = 1000005;
int n, m, num[maxn], fa[maxc], ans;
set<int> pos[maxc];
inline int iread() {
int f = 1, x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return f * x;
}
inline void merge(int a, int b) {
for(sit it = pos[a].begin(); it != pos[a].end(); it++) {
ans -= (num[*it - 1] == b) + (num[*it + 1] == b);
pos[b].insert(*it);
}
for(sit it = pos[a].begin(); it != pos[a].end(); it++)
num[*it] = b;
pos[a].clear();
}
int main() {
n = iread(); m = iread();
for(int i = 1; i <= n; i++) {
pos[num[i] = iread()].insert(i);
fa[num[i]] = num[i];
ans += (num[i] != num[i - 1]);
}
for(int i = 1; i <= m; i++) {
int opt = iread();
if(opt == 1) {
int u = iread(), v = iread();
if(u == v) continue;
if(pos[fa[u]].size() > pos[fa[v]].size()) swap(fa[u], fa[v]);
merge(fa[u], fa[v]);
} else printf("%d\n", ans);
}
return 0;
}