E. Cyclic Components

Description:
You are given an undirected graph consisting of n vertices and m edges. Your task is to find the number of connected components which are cycles.

Here are some definitions of graph theory.

An undirected graph consists of two sets: set of nodes (called vertices) and set of edges. Each edge connects a pair of vertices. All edges are bidirectional (i.e. if a vertex a is connected with a vertex b, a vertex b is also connected with a vertex a). An edge can’t connect vertex with itself, there is at most one edge between a pair of vertices.

Two vertices u and v belong to the same connected component if and only if there is at least one path along edges connecting u and v.

A connected component is a cycle if and only if its vertices can be reordered in such a way that:

• the first vertex is connected with the second vertex by an edge,
• the second vertex is connected with the third vertex by an edge,
• the last vertex is connected with the first vertex by an edge,
• all the described edges of a cycle are distinct.

A cycle doesn’t contain any other edges except described above. By definition any cycle contains three or more vertices.

There are 6 connected components, 2 of them are cycles: [7,10,16] and [5,11,9,15].
Input
The first line contains two integer numbers n and m (1≤n≤2⋅1e5, 0≤m≤2⋅1e5) — number of vertices and edges.

The following m lines contains edges: edge i is given as a pair of vertices vi, ui (1≤vi,ui≤n, ui≠vi). There is no multiple edges in the given graph, i.e. for each pair (vi,ui) there no other pairs (vi,ui) and (ui,vi) in the list of edges.

Output
Print one integer — the number of connected components which are also cycles.

Examples
input
5 4
1 2
3 4
5 4
3 5
output
1
input
17 15
1 8
1 12
5 11
11 9
9 15
15 5
4 13
3 13
4 3
10 16
7 10
16 7
14 3
14 4
17 6
output
2
Note
In the first example only component [3,4,5] is also a cycle.

The illustration above corresponds to the second example.

Problem solving:

Code:

#include <bits/stdc++.h>
using namespace std;
const int   maxn = 2e5 + 10;
int         n, m, in[maxn], f[maxn], ans, fa[maxn];
vector<int> V[maxn];
int find(int x)
{
return x != f[x] ? f[x] = find(f[x]) : x;
}
void join(int x, int y)
{
x = find(x), y = find(y);
if (x != y)
f[x] = y;
} //并查集
int main()
{
ios::sync_with_stdio(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
f[i] = i;
for (int i = 0, u, v; i < m; i++)
{
cin >> u >> v;
in[u]++, in[v]++; //预处理每个结点的度数
join(u, v);
}
for (int i = 1; i <= n; i++)
find(i);  //这一步是必须有的,因为我们处理的时候每个部分的父节点只有一个来表示，不加这一步的话可能导致明明是一个部分的点却被处理成了两个部分。如果还是不理解，可以注释之后输出f[i]和不注释的时候输出f[i]对比着看看。
for (int i = 1; i <= n; i++)
{
V[f[i]].push_back(i);  //把以f[i]为父节点的点存在一起
}
for (int i = 1; i <= n; i++)
{
if (V[i].size() == 0) //如果就没有以i为父节点的点，直接跳过
continue;
int flag = 1;
for (int j = 0; j < V[i].size(); j++)
{
if (in[V[i][j]] != 2)
{
flag = 0;
break;
}
} //如果连通块中的每个节点的度数都是2，答案才能加一
ans += flag;
}
cout << ans << endl;
}