题面
题解
- 什么是启发式合并?
小的合并到大的上面
复杂度(O(nlogn))
这题颜色的修改,即是两个序列的合并
考虑记录每个序列的(size)
小的合并到大的
存序列用链表
但是有一种情况,
(x->y)
(siz[x] > siz[y])
这个时候我们可以新建一个(f)数组,存一个真实颜色
碰到这种情况时,(swap(f[x], f[y]))
合并即是(f[x]->f[y])
Code
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 1e6+10;
int c[N], ans;
int f[N], nxt[N], last[N], st[N], siz[N];
void merge(int x, int y) {//x合并到y上
for (int i = last[x]; i; i = nxt[i]) ans -= (c[i-1] == y) + (c[i+1] == y);
for (int i = last[x]; i; i = nxt[i]) c[i] = y;
nxt[st[x]] = last[y], last[y] = last[x], siz[y] += siz[x];
last[x] = siz[x] = st[x] = 0;
}
int main() {
int n, m;
read(n), read(m);
for (int i = 1; i <= n; i++) {
read(c[i]);
ans += c[i] != c[i-1];
if (!last[c[i]]) st[c[i]] = i, f[c[i]] = c[i];
nxt[i] = last[c[i]], last[c[i]] = i, siz[c[i]]++;
}
while (m--) {
int opt; read(opt);
if (opt == 2) printf("%d
", ans);
else {
int x, y;
read(x), read(y);
if (x == y) continue;
if (siz[f[x]] > siz[f[y]]) swap(f[x], f[y]);
if (!siz[f[x]]) continue;
merge(f[x], f[y]);
}
}
return 0;
}