結果
| 問題 | No.2563 色ごとのグループ |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2023-12-02 15:37:07 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.89.0) |
| 結果 |
MLE
|
| 実行時間 | - |
| コード長 | 2,120 bytes |
| 記録 | |
| コンパイル時間 | 2,146 ms |
| コンパイル使用メモリ | 205,524 KB |
| 最終ジャッジ日時 | 2025-02-18 04:46:14 |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 11 MLE * 1 -- * 23 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 100009;
// Union-Find
// 計算量O(α(n))
struct UnionFind
{
int par[MAX_N]; // 親の番号
int rank[MAX_N];
// n要素で初期化
void init(int N)
{
for (int i = 0; i < N; i++)
{
par[i] = i; // 初めは全ての頂点が根
rank[i] = 0; // 初めは全ての頂点のランクが0
}
}
// 木の根を求める
int root(int x)
{
if (par[x] == x) // 根
return x;
else
return par[x] = root(par[x]); // 経路圧縮
}
// xとyが同じ集合に属するか否か
bool same(int x, int y)
{
return root(x) == root(y);
}
// xとyの属する集合を併合
void unite(int x, int y)
{
x = root(x);
y = root(y);
if (x == y) // 既に同じ集合に属するなら何もしない
return;
if (rank[x] < rank[y]) // xのrankの方が小さいとき
par[x] = y; // xをyを根としてつなぎ直す
else
{
par[y] = x; // yをxを根としてつなぎ直す
if (rank[x] == rank[y])
rank[x]++;
}
}
};
int main()
{
int N, M;
cin >> N >> M;
vector<set<int>> color(N, set<int>({}));
int C[N];
for (int i = 0; i < N; i++)
{
int c;
cin >> c;
c--;
C[i] = c;
color[c].insert(i);
}
vector<UnionFind> uf(N);
for (int i = 0; i < N; i++)
uf[i].init(N);
for (int i = 0; i < M; i++)
{
int u, v;
cin >> u >> v;
u--, v--;
if (C[u] == C[v])
uf[C[u]].unite(u, v);
}
int ans = 0;
for (int i = 0; i < N; i++)
{
auto itr1 = color[i].begin(), itr2 = itr1;
while (itr2 != color[i].end())
{
if (!uf[C[*itr1]].same(*itr1, *itr2))
{
uf[C[*itr1]].unite(*itr1, *itr2);
ans++;
}
itr2++;
}
}
cout << ans << endl;
}