ARC 097 D - Equals
- 問題
- 解法
頂点集合が、枝集合がである無向グラフを考える。このときGの2つの頂点が同じ連結成分に含まれるならはスワップを何回か繰り返すことで値を入れ替える事ができる事がわかる(解説pdf)。よって頂点とが同じ連結成分に含まれているようなの個数を数えれば良い。これはUnion-findを使っての時間計算量でできる。
#include <iostream> #include <string> #include <algorithm> #include <cstdio> #include <vector> #include <queue> #include <set> #include <numeric> #include <cmath> using namespace std; typedef long long int ll; const ll mod = 1e9+7; const ll INF = 1e9; const ll MAXN = 1e9; struct union_find{ vector<int> par,r; int n; union_find(){}; union_find(int x){ n = x; par.resize(n); r.resize(n); init(n); } void init(int n){ for(int i = 0; i < n; i++) par[i] = i; for(int i = 0; i < n; i++) r[i] = 0; } int find(int x){ if(par[x] == x) return x; else return find(par[x]); } void unite(int x,int y){ x = find(x); y = find(y); if(x == y){ return; }else if(r[x] < r[y]){ par[x] = y; }else{ par[y] = x; if(r[x] == r[y]) r[x]++; } } bool same(int x,int y){ return find(x) == find(y); } }; int main() { int n,m; cin >> n >> m; vector<int> p(n),x(m),y(m); for(int i = 0; i < n; i++){ cin >> p[i]; } for(int i = 0; i < m; i++){ cin >> x[i] >> y[i]; } union_find uf(n); for(int i = 0; i < m; i++){ uf.unite(x[i],y[i]); } int sol = 0; for(int i = 0; i < n; i++){ if(uf.same(i+1,p[i])) sol++; } cout << sol << endl; return 0; }