[CodeForces#376 C Socks] 并查集
题目链接:[CodeForces#376 C Socks]
题意描述:
Arseniy 有
N
双袜子,然后每双袜子都有一个初始颜色,第
解题思路:
首先,用并查集求出联通块。那么我们开始考虑一个联通块中的所有顶点的最少染色次数。显然,
将联通块中所有点的颜色变成联通块中出现最多
的那个颜色
,这种做法肯定是最少染色次数,不难证明的。
接下来,就是在联通块中统计求答案就好了。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200000 + 5;
int N, M, K, C[MAXN];
int fa[MAXN];
int belong[MAXN], tid;
vector<int> G[MAXN];
int Find(int x) { return fa[x] == -1 ? x : fa[x] = Find(fa[x]); }
void Union(int a, int b) {
a = Find(a), b = Find(b);
if(a != b) fa[b] = a;
}
int main() {
int u, v;
scanf("%d %d %d", &N, &M, &K);
for(int i = 1; i <= N; i++) scanf("%d", &C[i]), fa[i] = i;
memset(fa, -1, sizeof(fa));
for(int i = 1; i <= M; i++) {
scanf("%d %d", &u, &v);
Union(u, v);
}
tid = 0;
// 利用belong数组,O(1)离散化
memset(belong, -1, sizeof(belong));
for(int i = 1; i <= N; i++) {
if(belong[Find(i)] == -1) belong[Find(i)] = tid ++;
}
for(int i = 0; i < tid; i++) G[i].clear();
for(int i = 1; i <= N; i++) {
int id = belong[Find(i)];
G[id].push_back(i);
}
int Ans = 0;
for(int k = 0; k < tid; k++) {
int GSZ = G[k].size(), Max = 0;
/// 这里用cnt数组会TLE,因为数组太大,memset大数组耗时较长
map<int, int> cnt;
for(int i = 0; i < GSZ; i++) {
int& color = C[G[k][i]];
Max = max(Max, ++cnt[color]);
}
Ans += GSZ - Max;
}
printf("%d\n", Ans);
return 0;
}