Problem:
Problem K
  Counting Cycles
Given an undirected graph, count the number of simple cycles in the graph. Here, a simple cycle is a connected subgraph all of whose vertices have degree exactly two.
Input
The input consists of a single test case of the following format.
$n$ $m$
$u_1$ $v_1$
...
$u_m$ $v_m$
A test case represents an undirected graph $G$.
The first line shows the number of vertices $n$ ($3 \leq n \leq 100 000$) and the number of edges $m$ ($n - 1 \leq m \leq n + 15$). The vertices of the graph are numbered from $1$ to $n$.
The edges of the graph are specified in the following $m$ lines. Two integers $u_i$ and $v_i$ in the
$i$-th line of these m lines mean that there is an edge between vertices $u_i$ and $v_i$. Here, you can assume that $u_i < v_i$ and thus there are no self loops.
For all pairs of $i$ and $j$ ($i \ne j$), either $u_i \ne u_j$ or $v_i \ne v_j$ holds. In other words, there are no parallel edges.
You can assume that $G$ is connected.
Output
The output should be a line containing a single number that is the number of simple cycles in the graph.
Sample Input 1
4 5
1 2
1 3
1 4
2 3
3 4
Sample Output 1
3
Sample Input 2
7 9
1 2
1 3
2 4
2 5
3 6
3 7
2 3
4 5
6 7
Sample Output 2
3
Sample Input 3
4 6
1 2
1 3
1 4
2 3
2 4
3 4
Sample Output 3
7

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
 
int n,m;
vector<int> G[100001];
vector<int> mdfG[100001];
bool useless[100001];
int cutted[100001];
bool used[100001];
vector<int> route;
int cmp[100001];
int all=0;
int ans=0;
 
set<deque<int> > se;
 
void dfs(int v,int p){
    used[v]=true;
    route.push_back(v);
    for(int i=0;i<mdfG[v].size();i++){
        int next=mdfG[v][i];
        if(p!=next){
            if(!used[next]){
                dfs(next,v);
            }else{
                deque<int> tmp;
                int si=route.size()-1;
                while(route[si]!=next){
                    tmp.push_back(route[si]);
                    si--;
                }
                tmp.push_back(next);
                int best=next;
                for(int j=0;j<tmp.size();j++){
                    best=min(best,tmp[j]);
                }
                while(best!=tmp[0]){
                    int tp=tmp.front();
                    tmp.pop_front();
                    tmp.push_back(tp);
                }
                se.insert(tmp);
            }
        }
    }
    used[v]=false;
    route.pop_back();
}
 
int main(void){
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        a--;
        b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    if(m==n-1){
        printf("0\n");
    }else if(m==n){
        printf("1\n");
    }else{
        queue<int> que;
        memset(cmp,-1,sizeof(cmp));
        for(int i=0;i<n;i++){
            if(G[i].size()==1){
                que.push(i);
                useless[i]=true;
            }
        }
        while(que.size()){
            int v=que.front();
            que.pop();
            for(int i=0;i<G[v].size();i++){
                int next=G[v][i];
                cutted[next]++;
                if(!useless[next] && G[next].size()==cutted[next]+1){
                    useless[next]=true;
                    que.push(next);
                }
            }
        }
        for(int i=0;i<n;i++){
            if(G[i].size()-cutted[i]>=3){
                cmp[i]=all++;
                for(int j=0;j<G[i].size();j++){
                    int next=G[i][j];
                    if(useless[next])continue;
                    if(G[next].size()-cutted[next]<=2){
                        if(cmp[next]==-1){
                            cmp[next]=all++;
                            que.push(next);
                        }
                    }
                }
            }
        }
        if(que.size()==0){
            for(int i=0;i<n;i++){
                if(!useless[i]){
                    que.push(i);
                    cmp[i]=0;
                    all++;
                    break;
                }
            }
        }
        while(que.size()){
            int v=que.front();
            que.pop();
            for(int i=0;i<G[v].size();i++){
                if(cmp[G[v][i]]==-1 && !useless[G[v][i]]){
                    cmp[G[v][i]]=cmp[v];
                    que.push(G[v][i]);
                }
            }
        }
        for(int i=0;i<n;i++){
            if(useless[i])continue;
            for(int j=0;j<G[i].size();j++){
                if(cmp[i]!=cmp[G[i][j]] && !useless[G[i][j]])mdfG[cmp[i]].push_back(cmp[G[i][j]]);
            }
        }
        for(int i=0;i<all;i++){
            sort(mdfG[i].begin(),mdfG[i].end());
            mdfG[i].erase(unique(mdfG[i].begin(),mdfG[i].end()),mdfG[i].end());
        }
        dfs(0,-1);
        printf("%d\n",se.size()/2);
    }
    return 0;
}
accuracy: 1
time_ms: 500
memory_kb: 71520
final_rank: 11

code_snippet: // AOJ #1388 Counting Cycles
// 2025.3.3

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct Edge { int u, v; };

int n, m;
vector<vector<pair<int,int>>> adj;
vector<Edge> ed;

int tcnt = 0;
vector<int> d, low;
stack<int> st;
vector<vector<int>> bcc;

void dfs(int u, int par) {
    d[u] = low[u] = ++tcnt;
    for(auto &p : adj[u]){
        int v = p.first, id = p.second;
        if(d[v] == 0){
            st.push(id);
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] >= d[u]){
                vector<int> comp;
                while(true){
                    int cur = st.top();
                    st.pop();
                    comp.push_back(cur);
                    if(cur == id) break;
                }
                bcc.push_back(comp);
            }
        } else if(v != par && d[v] < d[u]){
            st.push(id);
            low[u] = min(low[u], d[v]);
        }
    }
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m;
    adj.resize(n+1);
    ed.resize(m);
    for (int i=0; i<m; i++){
        int u, v; cin >> u >> v;
        ed[i] = {u, v};
        adj[u].push_back({v, i});
        adj[v].push_back({u, i});
    }
    d.assign(n+1, 0);
    low.assign(n+1, 0);
    dfs(1, -1);
    while(!st.empty()){
        vector<int> comp;
        while(!st.empty()){
            comp.push_back(st.top());
            st.pop();
        }
        bcc.push_back(comp);
    }

    ll p2[30];
    p2[0] = 1;
    for (int i=1; i<30; i++) p2[i] = p2[i-1] << 1;


    ll ans = 0;
    for(auto &comp : bcc){
        unordered_set<int> S;
        int ecount = comp.size();
        for(auto id : comp){
            S.insert(ed[id].u);
            S.insert(ed[id].v);
        }
        int vcount = S.size();
        if(vcount < 3) continue;
        int r = ecount - (vcount - 1);
        if(r < 1) continue;
        ans += p2[r] - 1;
    }
    cout << ans << endl;
    return 0;
}
accuracy: 0.07407407407407407
time_ms: 30
memory_kb: 17040
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;

// ============================================================================================
// === Union Find Library
// ============================================================================================
class UnionFind {
    public:
    int size_ = 1;
    vector<int> par;

    void init(int sz) {
        size_ = sz + 1;
        par.resize(size_ + 2, -1);
    }

    int root(int pos) {
        if (par[pos] == -1) return pos;
        par[pos] = root(par[pos]);
        return par[pos];
    }

    void unite(int u, int v) {
        u = root(u);
        v = root(v);
        if (u != v) par[u] = v;
    }

    bool same(int u, int v) {
        if (root(u) == root(v)) return true;
        return false;
    }
};

// ============================================================================================
// === Variable / Function
// ============================================================================================
int N;
int M, U[1 << 19], V[1 << 19];
int Par[1 << 19];
int Dst[1 << 19];
bool Exist[1 << 19];
vector<int> G[1 << 19];
vector<int> H[109];

void dfs(int pos, int pre) {
    for (int to : G[pos]) {
        if (to == pre) continue;
        Dst[to] = Dst[pos] + 1;
        Par[to] = pos;
        dfs(to, pos);
    }
}

int lca(int u, int v) {
    if (Dst[u] > Dst[v]) swap(u, v);
    while (Dst[u] < Dst[v]) v = Par[v];
    while (u != v) {
        u = Par[u];
        v = Par[v];
    }
    return u;
}

vector<pair<int, int>> del_bridge(int smallN, vector<pair<int, int>> edges) {
    vector<pair<int, int>> ans;
    for (int i = 0; i < edges.size(); i++) {
        int cnt = 0; UnionFind UF; UF.init(smallN);
        for (int j = 0; j < edges.size(); j++) {
            if (i == j) continue;
            if (UF.same(edges[j].first, edges[j].second) == false) {
                UF.unite(edges[j].first, edges[j].second);
                cnt += 1;
            }
        }
        if (cnt == smallN - 1) ans.push_back(edges[i]);
    }
    return ans;
}

long long dfs2(int pos, int stt, long long mask) {
    long long ret = 0;
    for (int to : H[pos]) {
        if (to == stt) ret += 1;
        if (to <= stt) continue;
        if ((mask >> to) & 1) continue;
        ret += dfs2(to, stt, mask + (1LL << to));
    }
    return ret;
}

// ============================================================================================
// === Main Part
// ============================================================================================
int main() {
    // Step 1. Input
    cin >> N >> M;
    for (int i = 1; i <= M; i++) cin >> U[i] >> V[i];

    // Step 2. Solve
    UnionFind UF; UF.init(N + 2);
    vector<pair<int, int>> Special;
    vector<int> Verts;
    for (int i = 1; i <= M; i++) {
        if (UF.same(U[i], V[i]) == true) {
            Special.push_back(make_pair(U[i], V[i]));
            Verts.push_back(U[i]);
            Verts.push_back(V[i]);
        }
        else {
            UF.unite(U[i], V[i]);
            G[U[i]].push_back(V[i]);
            G[V[i]].push_back(U[i]);
        }
    }
    sort(Verts.begin(), Verts.end());
    Verts.erase(unique(Verts.begin(), Verts.end()), Verts.end());

    // Step 3. DFS
    dfs(1, -1);

    // Step 4. Get Vertex
    for (int i = 0; i < Verts.size(); i++) {
        Exist[Verts[i]] = true;
        for (int j = i + 1; j < Verts.size(); j++) {
            Exist[lca(Verts[i], Verts[j])] = true;
        }
    }
    Verts.clear();
    for (int i = 1; i <= N; i++) {
        if (Exist[i] == true) Verts.push_back(i);
    }

    // Step 5. Get Edges
    vector<pair<int, int>> Edges;
    for (pair<int, int> e : Special) {
        int pos1 = lower_bound(Verts.begin(), Verts.end(), e.first) - Verts.begin();
        int pos2 = lower_bound(Verts.begin(), Verts.end(), e.second) - Verts.begin();
        Edges.push_back(make_pair(pos1, pos2));
    }
    for (int idx : Verts) {
        int cx = idx;
        while (cx != 0) {
            cx = Par[cx];
            if (Exist[cx] == true) {
                int pos1 = lower_bound(Verts.begin(), Verts.end(), idx) - Verts.begin();
                int pos2 = lower_bound(Verts.begin(), Verts.end(), cx) - Verts.begin();
                Edges.push_back(make_pair(pos1, pos2));
                break;
            }
        }
    }
    sort(Edges.begin(), Edges.end());
    // Edges.erase(unique(Edges.begin(), Edges.end()), Edges.end());

    // Step 6. Delete Bridges
    int smallN = Verts.size();
    Edges = del_bridge(smallN, Edges);
    for (pair<int, int> e : Edges) {
        H[e.first].push_back(e.second);
        H[e.second].push_back(e.first);
    }

    // Step 7. Solve
    long long ans = 0;
    for (int stt = 0; stt < smallN; stt++) {
        long long ret = dfs2(stt, stt, (1LL << stt));
        ans += ret;
    }
    cout << (ans - (long long)Edges.size()) / 2LL << endl;
    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 31804
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;

// ============================================================================================
// === Union Find Library
// ============================================================================================
class UnionFind {
    public:
    int size_ = 1;
    vector<int> par;

    void init(int sz) {
        size_ = sz + 1;
        par.resize(size_ + 2, -1);
    }

    int root(int pos) {
        if (par[pos] == -1) return pos;
        par[pos] = root(par[pos]);
        return par[pos];
    }

    void unite(int u, int v) {
        u = root(u);
        v = root(v);
        if (u != v) par[u] = v;
    }

    bool same(int u, int v) {
        if (root(u) == root(v)) return true;
        return false;
    }
};

// ============================================================================================
// === Variable / Function
// ============================================================================================
int N;
int M, U[1 << 19], V[1 << 19];
int Par[1 << 19];
int Dst[1 << 19];
bool Exist[1 << 19];
vector<int> G[1 << 19];
vector<int> H[109];

void dfs(int pos, int pre) {
    for (int to : G[pos]) {
        if (to == pre) continue;
        Dst[to] = Dst[pos] + 1;
        Par[to] = pos;
        dfs(to, pos);
    }
}

int lca(int u, int v) {
    if (Dst[u] > Dst[v]) swap(u, v);
    while (Dst[u] < Dst[v]) v = Par[v];
    while (u != v) {
        u = Par[u];
        v = Par[v];
    }
    return u;
}

vector<pair<int, int>> del_bridge(int smallN, vector<pair<int, int>> edges) {
    vector<pair<int, int>> ans;
    for (int i = 0; i < edges.size(); i++) {
        int cnt = 0; UnionFind UF; UF.init(smallN);
        for (int j = 0; j < edges.size(); j++) {
            if (i == j) continue;
            if (UF.same(edges[j].first, edges[j].second) == false) {
                UF.unite(edges[j].first, edges[j].second);
                cnt += 1;
            }
        }
        if (cnt == smallN - 1) ans.push_back(edges[i]);
    }
    return ans;
}

long long dfs2(int pos, int stt, long long mask) {
    long long ret = 0;
    for (int to : H[pos]) {
        if (to == stt) ret += 1;
        if (to <= stt) continue;
        if ((mask >> to) & 1) continue;
        ret += dfs2(to, stt, mask + (1LL << to));
    }
    return ret;
}

// ============================================================================================
// === Main Part
// ============================================================================================
int main() {
    // Step 1. Input
    cin >> N >> M;
    for (int i = 1; i <= M; i++) cin >> U[i] >> V[i];

    // Step 2. Solve
    UnionFind UF; UF.init(N + 2);
    vector<pair<int, int>> Special;
    vector<int> Verts;
    for (int i = 1; i <= M; i++) {
        if (UF.same(U[i], V[i]) == true) {
            Special.push_back(make_pair(U[i], V[i]));
            Verts.push_back(U[i]);
            Verts.push_back(V[i]);
        }
        else {
            UF.unite(U[i], V[i]);
            G[U[i]].push_back(V[i]);
            G[V[i]].push_back(U[i]);
        }
    }
    sort(Verts.begin(), Verts.end());
    Verts.erase(unique(Verts.begin(), Verts.end()), Verts.end());

    // Step 3. DFS
    dfs(1, -1);

    // Step 4. Get Vertex
    for (int i = 0; i < Verts.size(); i++) {
        Exist[Verts[i]] = true;
        for (int j = i + 1; j < Verts.size(); j++) {
            Exist[lca(Verts[i], Verts[j])] = true;
        }
    }
    Verts.clear();
    for (int i = 1; i <= N; i++) {
        if (Exist[i] == true) Verts.push_back(i);
    }

    // Step 5. Get Edges
    vector<pair<int, int>> Edges;
    for (pair<int, int> e : Special) {
        int pos1 = lower_bound(Verts.begin(), Verts.end(), e.first) - Verts.begin();
        int pos2 = lower_bound(Verts.begin(), Verts.end(), e.second) - Verts.begin();
        Edges.push_back(make_pair(pos1, pos2));
    }
    for (int idx : Verts) {
        int cx = idx;
        while (cx != 0) {
            cx = Par[cx];
            if (Exist[cx] == true) {
                int pos1 = lower_bound(Verts.begin(), Verts.end(), idx) - Verts.begin();
                int pos2 = lower_bound(Verts.begin(), Verts.end(), cx) - Verts.begin();
                Edges.push_back(make_pair(pos1, pos2));
                break;
            }
        }
    }
    sort(Edges.begin(), Edges.end());
    Edges.erase(unique(Edges.begin(), Edges.end()), Edges.end());

    // Step 6. Delete Bridges
    int smallN = Verts.size();
    Edges = del_bridge(smallN, Edges);
    for (pair<int, int> e : Edges) {
        H[e.first].push_back(e.second);
        H[e.second].push_back(e.first);
    }

    // Step 7. Solve
    long long ans = 0;
    for (int stt = 0; stt < smallN; stt++) {
        long long ret = dfs2(stt, stt, (1LL << stt));
        ans += ret;
    }
    cout << (ans - (long long)Edges.size()) / 2LL << endl;
    return 0;
}
accuracy: 0.4074074074074074
time_ms: 80
memory_kb: 31012
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,a,b) for(ll i = a; i < b; i++)
#define all(a) (a).begin(), (a).end()

int loop_pon = 0;
vector<vector<int>> getgraph(){
    int n,m;
    cin >> n >> m;
    vector<multiset<int>> g(n);
    rep(i,0,m){
        int a,b;
        cin >> a >> b;
        a--,b--;
        g[a].insert(b);
        g[b].insert(a);
    }
    queue<int> sch;
    rep(i,0,n){
        sch.push(i);
    }
    vector<int> del(n,0);
    while(sch.size()){
        int nw = sch.front();
        sch.pop();
        if(del[nw]) continue;
        if(g[nw].size() == 1){
            int to = *g[nw].begin();
            g[to].erase(nw);
            g[nw].erase(to);
            del[nw] = 1;
            sch.push(to);
            continue;
        }
        if(g[nw].size() == 2) {
            int to1 = *g[nw].begin();
            int to2 = *next(g[nw].begin());
            if(to1 == to2) loop_pon++;
            else{
                g[to1].insert(to2);
                g[to2].insert(to1);
                sch.push(to2);
            }
            g[to1].erase(nw);
            g[to2].erase(nw);
            sch.push(to1);
            del[nw] = 1;
            continue;
        }
    }
    vector<int> index(n, -1);
    int nwind = 0;
    rep(i,0,n){
        if(!del[i] && g[i].size()) index[i] = nwind++;
    }
    vector<vector<int>> ng(nwind);
    rep(i,0,n){
        if(!del[i])
        for(auto to: g[i]){
            ng[index[i]].push_back(index[to]);
        }
    }
    return ng;
}

struct UF {
    int n;
    vector<int> par;
    UF(int _n): n(_n), par(_n, -1) {}
    int root(int a){
        if(par[a] < 0) return a;
        return par[a] = root(par[a]);
    }
    bool same(int a,int b){
        a = root(a);
        b = root(b);
        return a == b;
    }
    
    void unite(int a, int b){
        if(same(a, b)) return;
        a = root(a);
        b = root(b);
        par[a] = b;
        return;
    }

    bool is_con(){
        int r = root(0);
        rep(i,1,n){
            if(r != root(i)) return false;
        }
        return true;
    }
};

int main(){
    vector<vector<int>> g = getgraph();
    ll loop = loop_pon;
    int n = g.size();
    UF uf(n);

    vector<vector<int>> tree(n);
    vector<array<ll,2>> edge;
    rep(i,0,n){
        for(auto to: g[i]){
            if(i < to) continue;
            if(uf.same(i, to)){
                edge.push_back({i,(ll)to});
            }else{
                tree[i].push_back(to);
                tree[to].push_back(i);
                uf.unite(i, to);
            }
        }
    }

    int m = edge.size();
    
    int ans = loop;
    rep(i, 1, 1 << m){
        vector<vector<int>> data(n);
        vector<int> us;
        rep(j,0,m){
            if((i >> j) & 1){
                data[edge[j][0]].push_back(j);
                data[edge[j][1]].push_back(j);
                us.push_back(j);
            }
        }
        bool breaking = false;
        UF res(m);
        const auto dfs = [&](auto dfs, int nw, int par) -> int {
            if(breaking) return -1;
            for(auto to: tree[nw]){
                if(to == par) continue;
                int rr = dfs(dfs, to, nw);
                if(rr != -1){
                    data[nw].push_back(rr);
                }
            }
            if(data[nw].size() == 2){
                res.unite(data[nw][0], data[nw][1]);
                return -1;
            }
            if(data[nw].size() == 1){
                return data[nw][0];
            }
            if(data[nw].size() == 0){
                return -1;
            }
            breaking = true;
            return -1;
        };
        dfs(dfs,0,-1);
        bool con = true;
        rep(i,0,us.size() - 1){
            if(!res.same(us[i], us[i+1])) con = false;
        }
        if(!breaking && con){
            ans++;
        }
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 110
memory_kb: 18972
final_rank: 2

code_snippet: #include<bits/stdc++.h>
#define rep(i,s,n) for (int i = (int)(s); i < (int)(n); i++)
#define all(v) begin(v),end(v)
using namespace std;
using ll = long long;
bool chmin(auto &a, auto b){ return a > b ? a = b, 1 : 0; }
bool chmax(auto &a, auto b){ return a < b ? a = b, 1 : 0; }

using pii = pair<int,int>;

pair<vector<vector<int>>,vector<pii>> cpgraph() {
    int n, m; cin >> n >> m;
    vector<vector<int>> g(n);
    rep(i,0,m) {
        int u, v; cin >> u >> v; u--, v--;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    vector<bool> done(n,false);
    vector<pii> extra;
    vector<int> par(n), dep(n);
    set<pii> used;
    auto dfs = [&](auto sfs, int v) -> void {
        done[v] = true;
        for (int u : g[v]) {
            if (done[u]) {
                if (used.contains({u,v})) continue;
                if (u < v) extra.emplace_back(u,v);
            }
            else {
                par[u] = v;
                dep[u] = dep[v] + 1;
                used.insert({v,u});
                sfs(sfs,u);
            }
        }
    };
    par[0] = -1;
    dfs(dfs,0);
    // cout << "dfs" << endl;
    const int mx = 20;
    vector<vector<int>> to(mx,vector<int>(n,-1));
    rep(i,0,n) to[0][i] = par[i];
    rep(d,1,mx) {
        rep(i,0,n) {
            if (to[d-1][i] != -1) {
                to[d][i] = to[d-1][to[d-1][i]];
            }
        }
    }
    // cout << "to" << endl;
    auto lca = [&](int u, int v) {
        if (dep[u] > dep[v]) swap(u,v);
        int up = dep[v] - dep[u];
        for (int d = mx-1; d >= 0; d--) {
            if (up >> d & 1) {
                v = to[d][v];
            }
        }
        if (u == v) return u;
        for (int d = mx-1; d >= 0; d--) {
            if (to[d][u] != to[d][v]) {
                u = to[d][u];
                v = to[d][v];
            }
        }
        return par[u];
    };
    set<int> vs;
    for (auto [u, v] : extra) {
        vs.insert(u);
        vs.insert(v);
    }
    // cout << "vs insert" << endl;
    vector<int> ar;
    for (auto v : vs) ar.emplace_back(v);
    set<int> vss;
    int sz = ar.size();
    // cout << "lca start" << endl;
    // cout << sz << endl;
    rep(i,0,sz) rep(j,0,sz) {
        vss.insert(lca(ar[i],ar[j]));
    }
    // cout << "lca insert ok" << endl;
    vector<int> arr;
    for (auto v : vss) arr.emplace_back(v);
    vector<vector<int>> chs(n);
    rep(i,1,n) chs[par[i]].emplace_back(i);
    vector<int> down(n), up(n);
    int tm = 0;
    auto efs = [&](auto sfs, int v) -> void {
        down[v] = tm++;
        for (int u : chs[v]) {
            sfs(sfs,u);
        }
        up[v] = tm;
    };
    // cout << "efs start" << endl;
    efs(efs,0);
    // cout << "efs" << endl;
    sort(all(arr),[&](int l, int r) {
        return down[l] < down[r];
    });
    auto insubtree = [&](int r, int v) {
        return down[r] <= down[v] && up[v] <= up[r];
    };
    stack<int> st;
    int nn = arr.size();
    vector<vector<int>> ret(nn);
    auto add_edge = [&](int u, int v) {
        ret[u].emplace_back(v);
        ret[v].emplace_back(u);
    };
    map<int,int> mp;
    for (int i = 0; auto v : arr) {
        mp[v] = i++;
    }
    for (int v : arr) {
        while (!st.empty() && !insubtree(st.top(),v)) st.pop();
        if (!st.empty()) {
            add_edge(mp[st.top()],mp[v]);
        }
        st.push(v);
    }
    vector<pii> nextra;
    for (auto [u, v] : extra) {
        nextra.emplace_back(mp[u],mp[v]);
    }
    return {ret, nextra};
}

void solve() {
    auto [ikeru, es] = cpgraph();
    // cout << "ok" << endl; return ;
    for (auto [u, v]: es) {
        ikeru[u].push_back(v);
        ikeru[v].push_back(u);
    }

    int n = ikeru.size();
    // cout << "size " << n << endl;
    vector<bool> seen(n);
    ll ans = 0;
    auto dfs = [&](auto self, int i, int p, int st) -> void {
        int cnt = 0;
        for (int j: ikeru[i]) {
            if (j == p) {
                if (j == st) {
                    cnt += 1;
                }
                continue;
            }

            if (j == st) {
                ans++;
            }else if (j > st && !seen[j]) {
                seen[j] = 1;
                self(self, j, i, st);
                seen[j] = 0;
            }
        }
        ans += max(0, cnt - 1);
    };

    rep(i,0,n) {
        seen[i] = 1;
        dfs(dfs, i, -1, i);
    }

    cout << ans / 2 << endl;
}


int main() {
    cin.tie(0)->sync_with_stdio(0);
    solve();
}
accuracy: 1
time_ms: 60
memory_kb: 40860
final_rank: 5

code_snippet: #include <bits/stdc++.h>

#define rep(i,s,n) for(int i = int(s); i < int(n); i++)
#define rrep(i,s,n) for(int i = int(n) - 1; i >= int(s); i--)
#define all(v) (v).begin(), (v).end()

using ll = long long;
using ull = unsigned long long;
using ld = long double;

template<class T>
bool chmin(T &a, T b) {
    if(a <= b) return false;
    a = b;
    return true;
}

template<class T>
bool chmax(T &a, T b) {
    if(a >= b) return false;
    a = b;
    return true;
}

using namespace std;

struct dsu {
    public:
        dsu(int n = 0): _n(n), data(n,-1){}
        int leader(int a){
            if (data[a] < 0) return a;
            return data[a] = leader(data[a]);
        }

        int merge(int a, int b){
            int x = leader(a);
            int y = leader(b);
            if (x == y)return x;
            if (-data[x] < -data[y])swap(x, y);
            data[x] += data[y];
            data[y] = x;
            return x;
        }
        bool same(int a, int b){
            return leader(a) == leader(b);

        }
        int size(int a){
            return -data[leader(a)];
        }

    private:
        int _n;
        vector<int> data;
};

using pii = pair<int,int>;

int main() {
    std::cin.tie(nullptr);
    std::ios::sync_with_stdio(false);
    int n, m; cin >> n >> m;
    vector<vector<int>> g(n);
    dsu d(n);
    vector<pii> other;
    rep(i,0,m){
        int u, v; cin >> u >> v; u--, v--;
        if (d.same(u,v)){
            other.emplace_back(u,v);
        }
        else {
            d.merge(u,v);
            g[u].emplace_back(v);
            g[v].emplace_back(u);
        }
    }
    vector<int> par(n,-1), in(n), dep(n,0);
    int t = 0;
    auto dfs = [&](auto sfs, int v) -> void {
        in[v] = t++;
        for (int u : g[v]){
            if (par[v] == u) continue;
            par[u] = v;
            dep[u] = dep[v]+1;
            sfs(sfs,u);
        }
    };
    dfs(dfs,0);
    vector<int> a;
    for (auto [u, v] : other) a.emplace_back(u), a.emplace_back(v);
    sort(all(a),[&](int u, int v){
        return in[u] < in[v];
    });
    auto lca = [&](int u, int v){
        if (dep[u] < dep[v]) swap(u,v);
        while (dep[u] > dep[v]) u = par[u];
        while (u != v){
            u = par[u];
            v = par[v];
        }
        return u;
    };
    int sz = a.size();
    rep(i,0,sz) a.emplace_back(lca(a[i],a[(i+1)%sz]));
    sort(all(a),[&](int u, int v){
        return in[u] < in[v];
    });
    a.erase(unique(all(a)),a.end());
    sz = a.size();
    {
        vector<int> ids(n,-1);
        int id = 0;
        for (auto v : a) ids[v] = id++;
        vector<vector<int>> ng(sz);
        for (int v : a){
            int u = par[v];
            while (u != -1 && ids[u] == -1){
                u = par[u];
            }
            if (u == -1) continue;
            ng[ids[v]].emplace_back(ids[u]);
            ng[ids[u]].emplace_back(ids[v]);
        }
        for (auto [u, v] : other){
            ng[ids[v]].emplace_back(ids[u]);
            ng[ids[u]].emplace_back(ids[v]);
        }
        swap(g,ng);
    }
    //rep(v,0,sz) for (auto u : g[v]) cout << v << " " << u << endl;
    int ans = 0;
    rep(i,0,sz){
        vector<bool> done(sz,false);
        auto dfs = [&](auto sfs, int pre, int v) -> void {
            if (i == v && pre != -1){
                ans++;
                return ;
            }
            for (int u : g[v]){
                if (u < i) continue;
                if (u == i && pre != u){
                    sfs(sfs,v,u);
                }
                if (done[u]) continue;
                done[u] = true;
                sfs(sfs,v,u);
                done[u] = false;
            }
        };
        done[i] = true;
        dfs(dfs,-1,i);
    }
    cout << ans/2 << endl;
}
accuracy: 0.4074074074074074
time_ms: 70
memory_kb: 18120
final_rank: 12

code_snippet: #include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

int solve(int N, const vector<vector<int> >& G) {
	// step #1. create compressed graph
	vector<bool> vis(N, false);
	vector<int> par(N, -1);
	vector<int> depth(N);
	vector<int> ord(N, -1);
	int cnt = 0;
	vector<pair<int, int> > extras;
	auto build_tree = [&](auto& self, int pos, int pre) -> void {
		par[pos] = pre;
		vis[pos] = true;
		ord[pos] = cnt;
		cnt += 1;
		for (int i : G[pos]) {
			if (!vis[i]) {
				depth[i] = depth[pos] + 1;
				self(self, i, pos);
			}
			else if (i != pre && pos < i) {
				extras.push_back(make_pair(pos, i));
			}
		}
	};
	build_tree(build_tree, 0, -1);
	vector<int> v;
	for (pair<int, int> i : extras) {
		v.push_back(i.first);
		v.push_back(i.second);
	}
	sort(v.begin(), v.end(), [&](int va, int vb) { return ord[va] < ord[vb]; });
	int S1 = v.size();
	for (int i = 0; i < S1 - 1; i++) {
		int v1 = v[i], v2 = v[i + 1];
		while (v1 != v2) {
			if (depth[v1] < depth[v2]) {
				swap(v1, v2);
			}
			v1 = par[v1];
		}
		v.push_back(v1);
	}
	sort(v.begin(), v.end(), [&](int va, int vb) { return ord[va] < ord[vb]; });
	v.erase(unique(v.begin(), v.end()), v.end());
	int S2 = v.size();
	vector<int> mark(N, -1);
	for (int i = 0; i < S2; i++) {
		mark[v[i]] = i;
	}
	int edges = 0;
	vector<vector<int> > H(S2);
	for (int i = 0; i < v.size(); i++) {
		int u = v[i];
		do {
			u = par[u];
		} while (u != -1 && mark[u] == -1);
		if (u != -1) {
			H[i].push_back(mark[u]);
			H[mark[u]].push_back(i);
			edges += 1;
		}
	}
	for (pair<int, int> i : extras) {
		H[mark[i.first]].push_back(mark[i.second]);
		H[mark[i.second]].push_back(mark[i.first]);
		edges += 1;
	}

	// step #2. count cycles
	int answer = 0;
	vector<bool> track(S2, false);
	auto dfs = [&](auto& self, int pos, int ini) -> int {
		int res = 0;
		track[pos] = true;
		for (int i : H[pos]) {
			if (i < ini && !track[i]) {
				res += self(self, i, ini);
			}
			if (i == ini) {
				res += 1;
			}
		}
		track[pos] = false;
		return res;
	};
	for (int i = 0; i < S2; i++) {
		int res = dfs(dfs, i, i);
		answer += res;
	}
	answer = (answer - edges) / 2;
	return answer;
}

int main() {
	// step #1. input
	int N, M;
	cin >> N >> M;
	vector<vector<int> > G(N);
	for (int i = 0; i < M; i++) {
		int a, b;
		cin >> a >> b;
		a -= 1;
		b -= 1;
		G[a].push_back(b);
		G[b].push_back(a);
	}
	int answer = solve(N, G);
	cout << answer << endl;
	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 19332
final_rank: 1

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rrep(i, n) for (int i = (n) - 1; i >= 0; --i)

#define all(c) std::begin(c), std::end(c)

#ifdef LOCAL
#define debug(...) debug_impl(#__VA_ARGS__, __VA_ARGS__)
template <class T, class ...Args> void debug_impl(string s, T&& f, Args &&...args) {
    cerr << "(" << s << "): " << "(" << forward<T>(f);
    ((cerr << ", " << forward<Args>(args)), ..., (cerr << ")\n"));
}
#else
#define debug(...) void(0)
#endif

template <class T> bool chmax(T& a, const T& b) { return b > a ? (a = b, true) : false; }
template <class T> bool chmin(T& a, const T& b) { return b < a ? (a = b, true) : false; }


template <class T> istream& operator>>(istream& in, vector<T>& v) {
    for (auto& e : v) in >> e;
    return in;
}
template <class ...Args> void read(Args&... args) {
    (cin >> ... >> args);
}

template <class T> ostream& operator<<(ostream& out, const vector<T>& v) {
    int n = v.size();
    rep(i, n) {
        out << v[i];
        if (i + 1 != n) out << ' ';
    }
    return out;
}

template <class T, class ...Tails> void print(T&& h, Tails &&... tails) {
    cout << h, ((cout << ' ' << forward<Tails>(tails)), ..., (cout << '\n'));
}

int solve(vector<vector<int>> g) {
    const int n = g.size();

    if (n == 0) return 0;

    vector<pair<int, int>> es;

    vector<vector<int>> t(n);

    vector<int8_t> vis(n, false);
    auto make_dfs_tree = [&](auto make_dfs_tree, int u, int p) -> void {
        vis[u] = true;
        for (int v : g[u]) if (v != p) {
            if (vis[v]) {
                if (u < v) es.emplace_back(u, v);
            } else {
                t[u].push_back(v);
                t[v].push_back(u);
                make_dfs_tree(make_dfs_tree, v, u);
            }
        }
    };
    make_dfs_tree(make_dfs_tree, 0, -1);

    auto find_path = [&](int fr, int to) -> vector<int> {
        vector<int> path;

        auto dfs = [&](auto dfs, int u, int p) -> bool {
            path.push_back(u);
            if (u == to) return true;
            for (int v : t[u]) if (v != p) {
                if (dfs(dfs, v, u)) return true;
            }
            path.pop_back();
            return false;
        };
        dfs(dfs, fr, -1);

        return path;
    };

    vector<vector<pair<int, int>>> cycles;

    for (auto [u, v] : es) {
        vector<int> p = find_path(u, v);
        p.push_back(u);

        int siz = p.size() - 1;

        vector<pair<int, int>> cycle;
        rep(i, siz) {
            auto [x, y] = minmax(p[i], p[i + 1]);
            cycle.emplace_back(x, y);
        }
        sort(all(cycle));
        cycles.push_back(cycle);
    }

    const int k = cycles.size();

    debug(k);

    int ans = 0;

    rep(s, 1 << k) {
        if (s == 0) continue;

        vector<pair<int, int>> edges;

        rep(i, k) if ((s >> i) & 1) {
            vector<pair<int, int>> nedges;
            set_symmetric_difference(all(edges), all(cycles[i]), back_inserter(nedges));
            nedges.swap(edges);
        }

        vector<int8_t> induced(n, false);
        for (auto [u, v] : edges) {
            induced[u] = induced[v] = true;
        }

        vector<vector<int>> h(n);

        for (auto [u, v] : edges) {
            h[u].push_back(v);
            h[v].push_back(u);
        }
        vector<int8_t> vis(n, false);

        bool ok = true;
        rep(i, n) {
            if (induced[i]) {
                if (h[i].size() != 2) {
                    ok = false;
                    break;
                }
            } else {
                vis[i] = true;
            }
        }
        if (not ok) continue;

        rep(i, n) if (not vis[i]) {
            vis[i] = true;
            deque<int> dq { i };
            while (dq.size()) {
                int u = dq.front();
                dq.pop_front();
                for (int v : h[u]) {
                    if (not vis[v]) {
                        vis[v] = true;
                        dq.push_back(v);
                    }
                }
            }
            break;
        }

        ans += all_of(all(vis), [](auto e) { return e; });
    }

    return ans;
}

int main() {
    int n, m;
    read(n, m);

    vector<int> deg(n);

    vector<multiset<int>> g(n);
    rep(i, m) {
        int u, v;
        cin >> u >> v;
        --u, --v;
        g[u].insert(v);
        g[v].insert(u);
    }

    auto comp = [&](int i, int j) {
        return g[i].size() == g[j].size() ? i < j : g[i].size() < g[j].size();
    };

    set<int, decltype(comp)> pq{ comp };

    rep(i, n) {
        pq.insert(i);
    }

    int ans = 0;

    while (pq.size()) {
        int u = *pq.begin();

        if (g[u].size() >= 3) break;

        pq.erase(pq.begin());

        if (g[u].size() == 0) continue;

        if (g[u].size() == 1) {
            int v = *g[u].begin();
            pq.erase(v);
            g[u].erase(g[u].begin());
            g[v].erase(g[v].find(u));
            pq.insert(v);
        } else {
            int v = *g[u].begin();
            int w = *--g[u].end();

            if (g[v].count(w)) continue;

            g[u].erase(g[u].begin());
            g[u].erase(--g[u].end());
            g[v].erase(g[v].find(u));
            g[w].erase(g[w].find(u));

            if (v == w) {
                ++ans;
            } else {
                g[v].insert(w);
                g[w].insert(v);
            }
        }
    }

    vector<int> ids(n, -1);
    int nxt_id = 0;
    rep(i, n) {
        if (g[i].size() >= 2) {
            ids[i] = nxt_id++;
        }
    }

    debug(nxt_id);

    vector<vector<int>> g2(nxt_id);
    rep(i, n) if (ids[i] >= 0) {
        for (int j : g[i]) if (i < j) {
            int u = ids[i], v = ids[j];
            assert(v >= 0);
            g2[u].push_back(v);
            g2[v].push_back(u);
        }
    }

    ans += solve(g2);

    print(ans);
}
accuracy: 1
time_ms: 270
memory_kb: 22332
final_rank: 3

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rrep(i, n) for (int i = (n) - 1; i >= 0; --i)

#define all(c) std::begin(c), std::end(c)

#ifdef LOCAL
#define debug(...) debug_impl(#__VA_ARGS__, __VA_ARGS__)
template <class T, class ...Args> void debug_impl(string s, T&& f, Args &&...args) {
    cerr << "(" << s << "): " << "(" << forward<T>(f);
    ((cerr << ", " << forward<Args>(args)), ..., (cerr << ")\n"));
}
#else
#define debug(...) void(0)
#endif

template <class T> bool chmax(T& a, const T& b) { return b > a ? (a = b, true) : false; }
template <class T> bool chmin(T& a, const T& b) { return b < a ? (a = b, true) : false; }


template <class T> istream& operator>>(istream& in, vector<T>& v) {
    for (auto& e : v) in >> e;
    return in;
}
template <class ...Args> void read(Args&... args) {
    (cin >> ... >> args);
}

template <class T> ostream& operator<<(ostream& out, const vector<T>& v) {
    int n = v.size();
    rep(i, n) {
        out << v[i];
        if (i + 1 != n) out << ' ';
    }
    return out;
}

template <class T, class ...Tails> void print(T&& h, Tails &&... tails) {
    cout << h, ((cout << ' ' << forward<Tails>(tails)), ..., (cout << '\n'));
}

int solve(vector<vector<int>> g) {
    const int n = g.size();

    if (n == 0) return 0;

    vector<pair<int, int>> es;

    vector<vector<int>> t(n);

    vector<int8_t> vis(n, false);
    auto make_dfs_tree = [&](auto make_dfs_tree, int u, int p) -> void {
        vis[u] = true;
        for (int v : g[u]) if (v != p) {
            if (vis[v]) {
                if (u < v) es.emplace_back(u, v);
            } else {
                t[u].push_back(v);
                t[v].push_back(u);
                make_dfs_tree(make_dfs_tree, v, u);
            }
        }
    };
    make_dfs_tree(make_dfs_tree, 0, -1);

    auto find_path = [&](int fr, int to) -> vector<int> {
        vector<int> path;

        auto dfs = [&](auto dfs, int u, int p) -> bool {
            path.push_back(u);
            if (u == to) return true;
            for (int v : t[u]) if (v != p) {
                if (dfs(dfs, v, u)) return true;
            }
            path.pop_back();
            return false;
        };
        dfs(dfs, fr, -1);

        return path;
    };

    vector<vector<pair<int, int>>> cycles;

    for (auto [u, v] : es) {
        vector<int> p = find_path(u, v);
        p.push_back(u);

        int siz = p.size() - 1;

        vector<pair<int, int>> cycle;
        rep(i, siz) {
            auto [x, y] = minmax(p[i], p[i + 1]);
            cycle.emplace_back(x, y);
        }
        sort(all(cycle));
        cycles.push_back(cycle);
    }

    const int k = cycles.size();

    debug(k);

    int ans = 0;

    rep(s, 1 << k) {
        if (s == 0) continue;

        vector<pair<int, int>> edges;

        rep(i, k) if ((s >> i) & 1) {
            vector<pair<int, int>> nedges;
            set_symmetric_difference(all(edges), all(cycles[i]), back_inserter(nedges));
            nedges.swap(edges);
        }

        vector<int8_t> induced(n, false);
        for (auto [u, v] : edges) {
            induced[u] = induced[v] = true;
        }

        vector<vector<int>> h(n);

        for (auto [u, v] : edges) {
            h[u].push_back(v);
            h[v].push_back(u);
        }
        vector<int8_t> vis(n, false);

        bool ok = true;
        rep(i, n) {
            if (induced[i]) {
                if (h[i].size() != 2) {
                    ok = false;
                    break;
                }
            } else {
                vis[i] = true;
            }
        }
        if (not ok) continue;

        rep(i, n) if (not vis[i]) {
            vis[i] = true;
            deque<int> dq { i };
            while (dq.size()) {
                int u = dq.front();
                dq.pop_front();
                for (int v : h[u]) {
                    if (not vis[v]) {
                        vis[v] = true;
                        dq.push_back(v);
                    }
                }
            }
            break;
        }

        ans += all_of(all(vis), [](auto e) { return e; });
    }

    return ans;
}

int main() {
    int n, m;
    read(n, m);

    vector<int> deg(n);

    vector<multiset<int>> g(n);
    rep(i, m) {
        int u, v;
        cin >> u >> v;
        --u, --v;
        g[u].insert(v);
        g[v].insert(u);
    }

    auto comp = [&](int i, int j) {
        return g[i].size() == g[j].size() ? i < j : g[i].size() < g[j].size();
    };

    set<int, decltype(comp)> pq{ comp };

    rep(i, n) {
        pq.insert(i);
    }

    int ans = 0;

    while (pq.size()) {
        int u = *pq.begin();

        if (g[u].size() >= 3) break;

        debug(u);

        pq.erase(pq.begin());

        if (g[u].size() == 0) continue;

        if (g[u].size() == 1) {
            int v = *g[u].begin();
            pq.erase(v);
            g[u].erase(g[u].begin());
            g[v].erase(g[v].find(u));
            pq.insert(v);
        } else {
            int v = *g[u].begin();
            int w = *--g[u].end();

            g[u].erase(g[u].begin());
            g[u].erase(--g[u].end());
            g[v].erase(g[v].find(u));
            g[w].erase(g[w].find(u));

            if (v == w) {
                ++ans;
            } else {
                g[v].insert(w);
                g[w].insert(v);
            }
        }
    }

    vector<int> ids(n, -1);
    int nxt_id = 0;
    rep(i, n) {
        if (g[i].size() >= 3) {
            ids[i] = nxt_id++;
        }
    }

    vector<vector<int>> g2(nxt_id);
    rep(i, n) if (ids[i] >= 0) {
        for (int j : g[i]) if (i < j) {
            int u = ids[i], v = ids[j];
            assert(v >= 0);
            g2[u].push_back(v);
            g2[v].push_back(u);
        }
    }

    ans += solve(g2);

    print(ans);
}
accuracy: 0.07407407407407407
time_ms: 140
memory_kb: 22196
final_rank: 20

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rrep(i, n) for (int i = (n) - 1; i >= 0; --i)

#define all(c) std::begin(c), std::end(c)

#ifdef LOCAL
#define debug(...) debug_impl(#__VA_ARGS__, __VA_ARGS__)
template <class T, class ...Args> void debug_impl(string s, T&& f, Args &&...args) {
    cerr << "(" << s << "): " << "(" << forward<T>(f);
    ((cerr << ", " << forward<Args>(args)), ..., (cerr << ")\n"));
}
#else
#define debug(...) void(0)
#endif

template <class T> bool chmax(T& a, const T& b) { return b > a ? (a = b, true) : false; }
template <class T> bool chmin(T& a, const T& b) { return b < a ? (a = b, true) : false; }


template <class T> istream& operator>>(istream& in, vector<T>& v) {
    for (auto& e : v) in >> e;
    return in;
}
template <class ...Args> void read(Args&... args) {
    (cin >> ... >> args);
}

template <class T> ostream& operator<<(ostream& out, const vector<T>& v) {
    int n = v.size();
    rep(i, n) {
        out << v[i];
        if (i + 1 != n) out << ' ';
    }
    return out;
}

template <class T, class ...Tails> void print(T&& h, Tails &&... tails) {
    cout << h, ((cout << ' ' << forward<Tails>(tails)), ..., (cout << '\n'));
}

int solve(vector<vector<int>> g) {
    const int n = g.size();

    if (n == 0) return 0;

    vector<pair<int, int>> es;

    vector<vector<int>> t(n);

    vector<int8_t> vis(n, false);
    auto make_dfs_tree = [&](auto make_dfs_tree, int u, int p) -> void {
        vis[u] = true;
        for (int v : g[u]) if (v != p) {
            if (vis[v]) {
                if (u < v) es.emplace_back(u, v);
            } else {
                t[u].push_back(v);
                t[v].push_back(u);
                make_dfs_tree(make_dfs_tree, v, u);
            }
        }
    };
    make_dfs_tree(make_dfs_tree, 0, -1);

    auto find_path = [&](int fr, int to) -> vector<int> {
        vector<int> path;

        auto dfs = [&](auto dfs, int u, int p) -> bool {
            path.push_back(u);
            if (u == to) return true;
            for (int v : t[u]) if (v != p) {
                if (dfs(dfs, v, u)) return true;
            }
            path.pop_back();
            return false;
        };
        dfs(dfs, fr, -1);

        return path;
    };

    vector<vector<pair<int, int>>> cycles;

    for (auto [u, v] : es) {
        vector<int> p = find_path(u, v);
        p.push_back(u);

        int siz = p.size() - 1;

        vector<pair<int, int>> cycle;
        rep(i, siz) {
            auto [x, y] = minmax(p[i], p[i + 1]);
            cycle.emplace_back(x, y);
        }
        sort(all(cycle));
        cycles.push_back(cycle);
    }

    const int k = cycles.size();

    debug(k);

    int ans = 0;

    rep(s, 1 << k) {
        if (s == 0) continue;

        vector<pair<int, int>> edges;

        rep(i, k) if ((s >> i) & 1) {
            vector<pair<int, int>> nedges;
            set_difference(all(edges), all(cycles[i]), back_inserter(nedges));
            nedges.swap(edges);
        }

        vector<int8_t> induced(n, false);
        for (auto [u, v] : edges) {
            induced[u] = induced[v] = true;
        }

        vector<vector<int>> h(n);

        for (auto [u, v] : edges) {
            h[u].push_back(v);
            h[v].push_back(u);
        }
        vector<int8_t> vis(n, false);

        bool ok = true;
        rep(i, n) {
            if (induced[i]) {
                if (h[i].size() != 2) {
                    ok = false;
                    break;
                }
            } else {
                vis[i] = true;
            }
        }
        if (not ok) continue;

        rep(i, n) if (not vis[i]) {
            vis[i] = true;
            deque<int> dq { i };
            while (dq.size()) {
                int u = dq.front();
                dq.pop_front();
                for (int v : h[u]) {
                    if (not vis[v]) {
                        vis[v] = true;
                        dq.push_back(v);
                    }
                }
            }
            break;
        }

        ans += all_of(all(vis), [](auto e) { return e; });
    }

    return ans;
}

int main() {
    int n, m;
    read(n, m);

    vector<int> deg(n);

    vector<multiset<int>> g(n);
    rep(i, m) {
        int u, v;
        cin >> u >> v;
        --u, --v;
        g[u].insert(v);
        g[v].insert(u);
    }

    auto comp = [&](int i, int j) {
        return g[i].size() == g[j].size() ? i < j : g[i].size() < g[j].size();
    };

    set<int, decltype(comp)> pq{ comp };

    rep(i, n) {
        pq.insert(i);
    }

    int ans = 0;

    while (pq.size()) {
        int u = *pq.begin();

        if (g[u].size() >= 3) break;

        // debug(u);

        pq.erase(pq.begin());

        if (g[u].size() == 0) continue;

        if (g[u].size() == 1) {
            int v = *g[u].begin();
            pq.erase(v);
            g[u].erase(g[u].begin());
            g[v].erase(g[v].find(u));
            pq.insert(v);
        } else {
            int v = *g[u].begin();
            int w = *--g[u].end();

            g[u].erase(g[u].begin());
            g[u].erase(--g[u].end());
            g[v].erase(g[v].find(u));
            g[w].erase(g[w].find(u));

            if (v == w) {
                ++ans;
                // debug(ans);
            } else {
                g[v].insert(w);
                g[w].insert(v);
            }
        }
    }

    vector<int> ids(n, -1);
    int nxt_id = 0;
    rep(i, n) {
        if (g[i].size() >= 3) {
            ids[i] = nxt_id++;
        }
    }

    vector<vector<int>> g2(nxt_id);
    rep(i, n) if (ids[i] >= 0) {
        for (int j : g[i]) if (i < j) {
            int u = ids[i], v = ids[j];
            assert(v >= 0);
            g2[u].push_back(v);
            g2[v].push_back(u);
        }
    }

    // debug(ans);

    ans += solve(g2);

    print(ans);
}
accuracy: 0.07407407407407407
time_ms: 110
memory_kb: 22332
final_rank: 19

code_snippet: #line 1 "a.cpp"
/*	author:  Kite_kuma
	created: 2022.04.05 11:03:43 */

// #ifdef LOCAL
// #define _GLIBCXX_DEBUG
// #endif
#include <bits/stdc++.h>
using namespace std;

#pragma region macros

#define foa(s, v) for(auto &s : v)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define popcnt(n) __builtin_popcountll((long long)n)

#define REPname(a, b, c, d, e, ...) e
#define rep(...) REPname(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define REP0(x) for(int Counter_in_rep_macro = 0; Counter_in_rep_macro < (x); ++Counter_in_rep_macro)
#define REP1(i, x) for(int i = 0; i < (x); ++i)
#define REP2(i, l, r) for(int i = (l); i < (r); ++i)
#define REP3(i, l, r, c) for(int i = (l); i < (r); i += (c))

#define DREPname(a, b, c, d, e, ...) e
#define drep(...) DREPname(__VA_ARGS__, DREP3, DREP2, DREP1)(__VA_ARGS__)
#define DREP1(i, x) for(int i = (x)-1; i >= 0; --i)
#define DREP2(i, l, r) for(int i = (r)-1; i >= (l); --i)
#define DREP3(i, l, r, c) for(int i = (r)-1; i >= (l); i -= (c))

#pragma endregion

#pragma region aliases

using ll = long long;
using ld = long double;
using ull = unsigned long long;
using vi = std::vector<int>;
using vvi = std::vector<std::vector<int>>;
using vvvi = std::vector<std::vector<std::vector<int>>>;
using vll = std::vector<ll>;
using vvll = std::vector<vll>;
using vvvll = std::vector<vvll>;
using pii = std::pair<int, int>;
using pll = std::pair<long long, long long>;
template <class T = ll>
using V = std::vector<T>;
template <class T = ll>
using VV = V<V<T>>;
template <class T = ll>
using VVV = V<V<V<T>>>;
template <class T = ll>
using pqup = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <class T = ll>
using pqdn = std::priority_queue<T>;

#pragma endregion

#pragma region constants

const int inf = 1e9;
const long long INF = 1e18;
const long double pi = acos(-1);
const char dl = '\n';
const char sp = ' ';
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

const int mod_1000000007 = 1000000007;
const int mod_998244353 = 998244353;

#pragma endregion

#pragma region basic_operation

template <class T0, class T1, class T2>
inline bool in_range(T0 x, T1 lef, T2 rig) {
	return ((lef <= x) && (x < rig));
}

template <class T>
inline bool chmin(T &a, T b) {
	if(a > b) {
		a = b;
		return true;
	}
	return false;
}
template <class T>
inline bool chmax(T &a, T b) {
	if(a < b) {
		a = b;
		return true;
	}
	return false;
}

void Yes(bool f = 1) { std::cout << (f ? "Yes" : "No") << '\n'; }
void No() { std::cout << "No\n"; }
void YES(bool f = 1) { std::cout << (f ? "YES" : "NO") << '\n'; }
void NO() { std::cout << "NO\n"; }

template <class T>
void drop(T answer) {
	std::cout << answer << '\n';
	exit(0);
}

void err(bool flag = true) {
	if(!flag) return;
	std::cout << -1 << '\n';
	exit(0);
}

template <class T>
void vout(std::vector<T> const &v, bool vertically = 0) {
	if(vertically) {
		for(auto const &a : v) {
			std::cout << a << '\n';
		}
		return;
	}
	for(auto it = v.begin(); it != v.end(); it++) {
		std::cout << (*it);
		if(it != v.end() - 1) {
			std::cout << ' ';
		}
	}
	std::cout << '\n';
	return;
}

inline void print() { std::cout << '\n'; }
template <class T>
inline void print(T x) {
	std::cout << x << '\n';
	return;
}
template <typename Head, typename... Tail>
void print(Head H, Tail... T) {
	std::cout << H << " ";
	print(T...);
}

template <class T>
void add(std::vector<T> &v, T val) {
	for(auto &a : v) a += val;
	return;
}

template <class T>
T dup(T a, T b) {
	assert(b != 0);
	return (a + b - 1) / b;
}

template <class T>
T greatest_lower_multiple(T x, T d) {
	if(d == 0) return 0;
	if(d < 0) d *= -1;
	T y = x % d;
	if(y < 0) y += d;
	return x - y;
}

template <class T>
T least_upper_multiple(T x, T d) {
	return -greatest_lower_multiple(-x, d);
}

long long POW(long long a, long long n) {
	long long res = 1;
	while(n > 0) {
		if(n & 1) res = res * a;
		a = a * a;
		n >>= 1;
	}
	return res;
}

long long modpow(long long a, long long n, long long mod) {	 // a^n mod
	assert(n >= 0 && mod);
	if(mod == 1) return 0LL;
	long long res = 1;
	a %= mod;
	while(n > 0) {
		if(n & 1) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res < 0 ? res + mod : res;
}

// return x which satisfies a * x % mod == gcd(a, mod)
// not (mod | a)
long long modinv(long long a, long long mod) {
	long long b = mod, u = 1, v = 0;
	while(b) {
		long long t = a / b;
		a -= t * b;
		std::swap(a, b);
		u -= t * v;
		std::swap(u, v);
	}
	u %= mod;
	if(u < 0) u += mod;
	return u;
}

template <class T>
int lb(const std::vector<T> &a, const T x) {
	return std::distance(a.begin(), std::lower_bound(a.begin(), a.end(), x));
}
template <class T>
int ub(const std::vector<T> &a, const T x) {
	return std::distance(a.begin(), std::upper_bound(a.begin(), a.end(), x));
}
template <class T>
void unq_sort(std::vector<T> &a) {
	std::sort(a.begin(), a.end());
	a.erase(std::unique(a.begin(), a.end()), a.end());
}
template <class T>
std::vector<int> press(std::vector<T> &a) {
	auto vec = a;
	unq_sort(vec);
	std::vector<int> ret;
	for(auto &v : a) ret.push_back(lb(vec, v));
	return ret;
}

#pragma endregion

#pragma region input
#define VEC(type, name, size) \
	vector<type> name(size);  \
	scanner::INPUT(name)
#define VVEC(type, name, h, w)                     \
	vector<vector<type>> name(h, vector<type>(w)); \
	scanner::INPUT(name)
#define INT(...)     \
	int __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LL(...)            \
	long long __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define STR(...)        \
	string __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define CHR(...)      \
	char __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define DBL(...)        \
	double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LD(...)              \
	long double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define TPL3(type0, type1, type2, name)   \
	std::tuple<type0, type1, type2> name; \
	scanner::INPUT(name);
#define TPL4(type0, type1, type2, type3, name)   \
	std::tuple<type0, type1, type2, type3> name; \
	scanner::INPUT(name);

namespace scanner {
template <class T>
void scan(T &a) {
	std::cin >> a;
}

template <class T, class L>
void scan(std::pair<T, L> &p) {
	scan(p.first);
	scan(p.second);
}

template <class T0, class T1, class T2>
void scan(std::tuple<T0, T1, T2> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	scan(t0);
	scan(t1);
	scan(t2);
	p = std::make_tuple(t0, t1, t2);
}

template <class T0, class T1, class T2, class T3>
void scan(std::tuple<T0, T1, T2, T3> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	T3 t3;
	scan(t0);
	scan(t1);
	scan(t2);
	scan(t3);
	p = std::make_tuple(t0, t1, t2, t3);
}

template <class T>
void scan(std::vector<T> &a) {
	for(auto &i : a) scan(i);
}

void INPUT() {}
template <class Head, class... Tail>
void INPUT(Head &head, Tail &... tail) {
	scan(head);
	INPUT(tail...);
}
}  // namespace scanner

template <typename T1, typename T2>
std::istream &operator>>(std::istream &is, std::pair<T1, T2> &p) {
	is >> p.first >> p.second;
	return is;
}
#pragma endregion

#pragma region debug

#pragma region output
template <typename T1, typename T2>
std::ostream &std::operator<<(std::ostream &os, const std::pair<T1, T2> &p) {
	os << p.first << " " << p.second;
	return os;
}
template <class T>
std::ostream &std::operator<<(std::ostream &os, const std::vector<T> &v) {
	for(int i = 0; i < (int)v.size(); i++) {
		if(i) os << " ";
		os << v[i];
	}
	return os;
}
#pragma endregion

#pragma region view

namespace viewer {
void view(const long long e) {
	if(e == INF)
		std::cerr << "INF";
	else if(e == -INF)
		std::cerr << "-INF";
	else
		std::cerr << e;
}

void view(const int e) {
	if(e == inf)
		std::cerr << "inf";
	else if(e == -inf)
		std::cerr << "-inf";
	else
		std::cerr << e;
}

template <typename T>
void view(const T e) {
	std::cerr << e;
}

template <typename T, typename U>
void view(const std::pair<T, U> &p) {
	std::cerr << "(";
	view(p.first);
	std::cerr << ", ";
	view(p.second);
	std::cerr << ")";
}

template <class T0, class T1, class T2>
void view(const std::tuple<T0, T1, T2> &p) {
	std::cerr << "(";
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ")";
}

template <class T0, class T1, class T2, class T3>
void view(const std::tuple<T0, T1, T2, T3> &p) {
	std::cerr << "(";
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ", ";
	view(std::get<3>(p));
	std::cerr << ")";
}

template <typename T>
void view(const std::set<T> &s) {
	if(s.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(auto &t : s) {
		view(t);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::unordered_set<T> &s) {
	if(s.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(auto &t : s) {
		view(t);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::vector<T> &v) {
	if(v.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(const auto &e : v) {
		view(e);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::vector<std::vector<T>> &vv) {
	std::cerr << "{\n";
	for(const auto &v : vv) {
		std::cerr << "\t";
		view(v);
		std::cerr << '\n';
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::vector<std::pair<T, U>> &v) {
	std::cerr << "{\n";
	for(const auto &c : v) {
		std::cerr << "\t(";
		view(c.first);
		std::cerr << ", ";
		view(c.second);
		std::cerr << ")\n";
	}
	std::cerr << "}";
}

template <class T0, class T1, class T2>
void view(const std::vector<std::tuple<T0, T1, T2>> &v) {
	if(v.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << '{';
	for(const auto &t : v) {
		std::cerr << "\n\t";
		view(t);
		std::cerr << ",";
	}
	std::cerr << "\n}";
}

template <class T0, class T1, class T2, class T3>
void view(const std::vector<std::tuple<T0, T1, T2, T3>> &v) {
	if(v.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << '{';
	for(const auto &t : v) {
		std::cerr << "\n\t";
		view(t);
		std::cerr << ",";
	}
	std::cerr << "\n}";
}

template <typename T, typename U>
void view(const std::map<T, U> &m) {
	std::cerr << "{\n";
	for(const auto &t : m) {
		std::cerr << "\t[";
		view(t.first);
		std::cerr << "] : ";
		view(t.second);
		std::cerr << '\n';
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::unordered_map<T, U> &m) {
	std::cerr << "{\n";
	for(const auto &t : m) {
		std::cerr << "\t[";
		view(t.first);
		std::cerr << "] : ";
		view(t.second);
		std::cerr << '\n';
	}
	std::cerr << "}";
}
}  // namespace viewer

#pragma endregion

// when debugging : g++ foo.cpp -DLOCAL
#ifdef LOCAL
void debug_out() {}
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
	viewer::view(H);
	std::cerr << ", ";
	debug_out(T...);
}
#define debug(...)                                                \
	do {                                                          \
		std::cerr << __LINE__ << " [" << #__VA_ARGS__ << "] : ["; \
		debug_out(__VA_ARGS__);                                   \
		std::cerr << "\b\b]\n";                                   \
	} while(0)
#define dump(x)                                      \
	do {                                             \
		std::cerr << __LINE__ << " " << #x << " : "; \
		viewer::view(x);                             \
		std::cerr << '\n';                           \
	} while(0)

#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

#pragma endregion

#line 9 "SPJ-Library/graph/graph.hpp"

#pragma region graph

template <class cost_type = long long>
class graph {
   public:
	struct edge {
	   public:
		int from, to;
		cost_type cost;
		int id;
		edge() = default;
		edge(int from_, int to_, cost_type cost_ = 1, int id_ = -1) : from(from_), to(to_), cost(cost_), id(id_) {}
		bool operator<(const edge &a) const { return cost < a.cost; }
		bool operator>(const edge &a) const { return cost > a.cost; }
		friend std::ostream &operator<<(std::ostream &s, const edge &a) {
			s << '(' << a.from << " -> " << a.to << "), cost: " << a.cost << ", id: " << a.id;
			return s;
		}
	};

   private:
	std::vector<std::vector<edge>> edges;
	int next_edge_id = 0;

   public:
	inline const std::vector<edge> &operator[](int k) const { return edges[k]; }
	inline std::vector<edge> &operator[](int k) { return edges[k]; }

	int size() const { return int(edges.size()); }
	void resize(const int n) { edges.resize(n); }
	int edge_count() const { return next_edge_id; }

	friend std::ostream &operator<<(std::ostream &s, const graph<cost_type> &g) {
		for(const auto &adj : g.edges)
			for(const auto &ed : adj) s << ed << '\n';
		return s;
	}

	graph() = default;
	graph(int n) : edges(n) {}
	graph(int n, int e, bool weight = 0, bool directed = 0, int idx = 1) : edges(n) { input(e, weight, directed, idx); }
	const cost_type INF = std::numeric_limits<cost_type>::max() / 3;

	void input(int e = -1, bool weight = false, bool directed = false, int idx = 1) {
		if(e == -1) e = size() - 1;
		while(e--) {
			int u, v;
			std::cin >> u >> v;
			cost_type cost = 1;
			if(weight) std::cin >> cost;
			add_edge(u, v, cost, directed, idx);
		}
	}

	inline int add_edge(int u, int v, cost_type cost = 1, bool directed = false, int idx = 0) {
		u -= idx, v -= idx;
		edges[u].emplace_back(u, v, cost, next_edge_id);
		if(!directed && u != v) edges[v].emplace_back(v, u, cost, next_edge_id);
		return next_edge_id++;
	}

	// Ο(V+E)
	std::vector<cost_type> bfs(int s) {
		std::vector<cost_type> dist(size(), INF);
		std::queue<int> que;
		dist[s] = 0;
		que.push(s);
		while(!que.empty()) {
			int v = que.front();
			que.pop();
			for(auto &e : edges[v]) {
				if(dist[e.to] != INF) continue;
				dist[e.to] = dist[v] + e.cost;
				que.push(e.to);
			}
		}
		return dist;
	}

	// Ο(V+E)
	// constraint: cost of each edge is zero or one
	std::vector<cost_type> zero_one_bfs(int s) {
		std::vector<cost_type> dist(size(), INF);
		std::deque<int> deq;
		dist[s] = 0;
		deq.push_back(s);
		while(!deq.empty()) {
			int v = deq.front();
			deq.pop_front();
			for(auto &e : edges[v]) {
				assert(0LL <= e.cost and e.cost < 2LL);
				if(e.cost and dist[e.to] > dist[v] + 1) {
					dist[e.to] = dist[v] + 1;
					deq.push_back(e.to);
				} else if(!e.cost and dist[e.to] > dist[v]) {
					dist[e.to] = dist[v];
					deq.push_front(e.to);
				}
			}
		}
		return dist;
	}

	// Ο((E+V) lg E)
	// unreachable: INF
	std::vector<cost_type> dijkstra(int s) {  // verified
		std::vector<cost_type> dist(size(), INF);
		const auto compare = [](const std::pair<cost_type, int> &a, const std::pair<cost_type, int> &b) { return a.first > b.first; };
		std::priority_queue<std::pair<cost_type, int>, std::vector<std::pair<cost_type, int>>, decltype(compare)> que{compare};
		dist[s] = 0;
		que.emplace(0, s);
		while(!que.empty()) {
			std::pair<cost_type, int> p = que.top();
			que.pop();
			int v = p.second;
			if(dist[v] < p.first) continue;
			for(auto &e : edges[v]) {
				if(dist[e.to] > dist[v] + e.cost) {
					dist[e.to] = dist[v] + e.cost;
					que.emplace(dist[e.to], e.to);
				}
			}
		}
		return dist;
	}

	// Ο(VE)
	// unreachable: INF
	// reachable via negative cycle: -INF
	std::vector<cost_type> bellman_ford(int s) {
		int n = size();
		std::vector<cost_type> res(n, INF);
		res[s] = 0;
		for(int loop = 0; loop < n - 1; loop++) {
			for(int v = 0; v < n; v++) {
				if(res[v] == INF) continue;
				for(auto &e : edges[v]) {
					res[e.to] = std::min(res[e.to], res[v] + e.cost);
				}
			}
		}
		std::queue<int> que;
		std::vector<int> chk(n);
		for(int v = 0; v < n; v++) {
			if(res[v] == INF) continue;
			for(auto &e : edges[v]) {
				if(res[e.to] > res[v] + e.cost and !chk[e.to]) {
					que.push(e.to);
					chk[e.to] = 1;
				}
			}
		}
		while(!que.empty()) {
			int now = que.front();
			que.pop();
			for(auto &e : edges[now]) {
				if(!chk[e.to]) {
					chk[e.to] = 1;
					que.push(e.to);
				}
			}
		}
		for(int i = 0; i < n; i++)
			if(chk[i]) res[i] = -INF;
		return res;
	}

	// Ο(V^3)
	std::vector<std::vector<cost_type>> warshall_floyd() {
		int n = size();
		std::vector<std::vector<cost_type>> dist(n, std::vector<cost_type>(n, INF));
		for(int i = 0; i < n; i++) dist[i][i] = 0;
		for(int i = 0; i < n; i++)
			for(auto &e : edges[i]) dist[i][e.to] = std::min(dist[i][e.to], e.cost);
		for(int k = 0; k < n; k++)
			for(int i = 0; i < n; i++) {
				if(dist[i][k] == INF) continue;
				for(int j = 0; j < n; j++) {
					if(dist[k][j] == INF) continue;
					dist[i][j] = std::min(dist[i][j], dist[i][k] + dist[k][j]);
				}
			}
		return dist;
	}

	// Ο(V) (using DFS)
	// if a cycle exists, return {}
	std::vector<int> topological_sort() {
		std::vector<int> res;
		int n = size();
		std::vector<int> used(n, 0);
		bool not_DAG = false;
		auto dfs = [&](auto self, int k) -> void {
			if(not_DAG) return;
			if(used[k]) {
				if(used[k] == 1) not_DAG = true;
				return;
			}
			used[k] = 1;
			for(auto &e : edges[k]) self(self, e.to);
			used[k] = 2;
			res.push_back(k);
		};
		for(int i = 0; i < n; i++) dfs(dfs, i);
		if(not_DAG) return std::vector<int>{};
		std::reverse(res.begin(), res.end());
		return res;
	}

	bool is_dag() { return !topological_sort().empty(); }

	// Ο(V)
	// array of the distance to the most distant vertex
	// constraint: the graph is a tree
	std::vector<cost_type> height() {
		auto vec1 = bfs(0);
		int v1 = -1, v2 = -1;
		cost_type dia = -1;
		for(int i = 0; i < int(size()); i++)
			if(dia < vec1[i]) dia = vec1[i], v1 = i;
		vec1 = bfs(v1);
		dia = -1;
		for(int i = 0; i < int(size()); i++)
			if(dia < vec1[i]) dia = vec1[i], v2 = i;
		auto vec2 = bfs(v2);
		for(int i = 0; i < int(size()); i++) {
			if(vec1[i] < vec2[i]) vec1[i] = vec2[i];
		}
		return vec1;
	}

	// O(V+E)
	// vector<(int)(0 or 1)>
	// if it is not bipartite, return {}
	std::vector<int> bipartite_grouping() {
		std::vector<int> colors(size(), -1);
		auto dfs = [&](auto self, int now, int col) -> bool {
			colors[now] = col;
			for(auto &e : edges[now]) {
				if(col == colors[e.to]) return false;
				if(colors[e.to] == -1 and !self(self, e.to, !col)) return false;
			}
			return true;
		};
		for(int i = 0; i < int(size()); i++)
			if(!colors[i] and !dfs(dfs, i, 0)) return std::vector<int>{};
		return colors;
	}

	bool is_bipartite() { return !bipartite_grouping().empty(); }

	// Ο(V+E)
	// (v1, v2, diameter)
	std::tuple<int, int, cost_type> diameter() {
		std::vector<cost_type> dist = bfs(0);
		auto it = std::max_element(dist.begin(), dist.end());
		const int v = it - dist.begin();
		dist = bfs(v);
		it = std::max_element(dist.begin(), dist.end());
		return std::make_tuple(v, int(it - dist.begin()), *it);
	}

	// Ο(ElgE)
	cost_type prim() {
		cost_type res = 0;
		std::priority_queue<edge, std::vector<edge>, std::greater<edge>> que;
		for(auto &e : edges[0]) que.push(e);
		std::vector<int> chk(size());
		chk[0] = 1;
		int cnt = 1;
		while(cnt < size()) {
			auto e = que.top();
			que.pop();
			if(chk[e.to]) continue;
			cnt++;
			res += e.cost;
			chk[e.to] = 1;
			for(auto &e2 : edges[e.to]) que.push(e2);
		}
		return res;
	}

	// Ο(ElgE)
	cost_type kruskal() {
		std::vector<std::tuple<int, int, cost_type>> edges;
		for(int i = 0; i < int(size()); i++)
			for(auto &e : edges[i]) edges.emplace_back(i, e.to, e.cost);
		std::sort(edges.begin(), edges.end(), [](const std::tuple<int, int, cost_type> &a, const std::tuple<int, int, cost_type> &b) {
			return std::get<2>(a) < std::get<2>(b);
		});
		std::vector<int> uf_data(size(), -1);
		auto root = [&uf_data](auto self, int x) -> int {
			if(uf_data[x] < 0) return x;
			return uf_data[x] = self(self, uf_data[x]);
		};
		auto unite = [&uf_data, &root](int u, int v) -> bool {
			u = root(root, u), v = root(root, v);
			if(u == v) return false;
			if(uf_data[u] > uf_data[v]) std::swap(u, v);
			uf_data[u] += uf_data[v];
			uf_data[v] = u;
			return true;
		};
		cost_type ret = 0;
		for(auto &e : edges)
			if(unite(std::get<0>(e), std::get<1>(e))) ret += std::get<2>(e);
		return ret;
	}

	// O(V)
	std::vector<int> centroid() {
		int n = size();
		std::vector<int> centroid, sz(n);
		auto dfs = [&](auto self, int now, int per) -> void {
			sz[now] = 1;
			bool is_centroid = true;
			for(auto &e : edges[now]) {
				if(e.to != per) {
					self(self, e.to, now);
					sz[now] += sz[e.to];
					if(sz[e.to] > n / 2) is_centroid = false;
				}
			}
			if(n - sz[now] > n / 2) is_centroid = false;
			if(is_centroid) centroid.push_back(now);
		};
		dfs(dfs, 0, -1);
		return centroid;
	}

	// O(V+E)
	// bridge: (s, t)  (s < t);
	std::pair<std::vector<std::pair<int, int>>, std::vector<int>> bridges_and_articulations() {	 // verified
		std::vector<int> order(size(), -1), low(size()), articulation;
		int order_next = 0;
		std::vector<std::pair<int, int>> bridge;
		auto dfs = [&](auto self, int now, int par = -1) -> void {
			low[now] = order[now] = order_next++;
			bool is_articulation = false;
			int cnt = 0;
			for(auto &ed : edges[now]) {
				int &nxt = ed.to;
				if(nxt == par) continue;
				if(order[nxt] == -1) {
					cnt++;
					self(self, nxt, now);
					if(order[now] < low[nxt]) bridge.push_back(std::minmax(now, nxt));
					if(order[now] <= low[nxt]) is_articulation = true;
					low[now] = std::min(low[now], low[nxt]);
				} else if(order[now] > order[nxt]) {
					low[now] = std::min(low[now], order[nxt]);
				}
			}
			if(par == -1 and cnt < 2) is_articulation = false;
			if(is_articulation) articulation.push_back(now);
			return;
		};
		for(int i = 0; i < (int)size(); i++)
			if(order[i] == -1) dfs(dfs, i);
		return std::make_pair(bridge, articulation);
	}

	// Ο(V+E)
	// directed graph from root to leaf
	graph root_to_leaf(int root = 0) {
		graph res(size());
		std::vector<int> chk(size(), 0);
		chk[root] = 1;
		auto dfs = [&](auto self, int now) -> void {
			for(auto &e : edges[now]) {
				if(chk[e.to] == 1) continue;
				chk[e.to] = 1;
				res.add_edge(now, e.to, e.cost, 1, 0);
				self(self, e.to);
			}
		};
		dfs(dfs, root);
		return res;
	}

	// Ο(V+E)
	// directed graph from leaf to root
	graph leaf_to_root(int root = 0) {
		graph res(size());
		std::vector<int> chk(size(), 0);
		chk[root] = 1;
		auto dfs = [&](auto self, int now) -> void {
			for(auto &e : edges[now]) {
				if(chk[e.to] == 1) continue;
				chk[e.to] = 1;
				res.add_edge(e.to, now, e.cost, 1, 0);
				self(self, e.to);
			}
		};
		dfs(dfs, root);
		return res;
	}

	// cost_type Chu_Liu_Edmonds(int root = 0) {}
};
#pragma endregion
#line 553 "a.cpp"

#pragma region union_find

struct UF {
   private:
	std::vector<int> data;	// data[root] = -size, data[not_root] = parent

   public:
	int components;	 // number of components

	UF(int N) : data(N, -1), components(N) {}

	int root(int x) {
		if(data[x] < 0) return x;
		return data[x] = root(data[x]);
	}

	bool same(int x, int y) { return root(x) == root(y); }

	bool unite(int x, int y) {	// merge x and y
		x = root(x);
		y = root(y);
		if(x == y) return false;
		components--;
		if(data[x] > data[y]) std::swap(x, y);	// balancing
		data[x] += data[y];
		data[y] = x;
		return true;
	}

	int size(int x) { return -data[root(x)]; }

	std::vector<std::vector<int>> groups() {
		std::vector<std::vector<int>> g(data.size()), ret;
		for(size_t i = 0; i < data.size(); i++) g[root(i)].push_back((int)i);
		for(auto &vec : g)
			if(!vec.empty()) ret.push_back(vec);
		return ret;
	}
};

#pragma endregion

int solve(int n, int m) {
	graph<int> h(n);
	UF uf(n);
	vector<pair<int, int>> chords;
	vector<int> check(n);
	rep(m) {
		int a, b;
		cin >> a >> b;
		--a, --b;
		if(uf.unite(a, b)) {
			h.add_edge(a, b);
		} else {
			chords.emplace_back(a, b);
			check[a] = 1;
			check[b] = 1;
		}
	}
	if(m == n - 1) return 0;
	graph<int> g(n);
	int nxt_id = 0;
	vector<int> original_vertex_id;
	vector<int> original_to_converted(n, -1);
	auto dfs = [&](auto self, int now, int par) -> int {
		vector<int> unders;
		foa(e, h[now]) {
			if(e.to == par) continue;
			const int id_under = self(self, e.to, now);
			if(id_under == -1) continue;
			unders.push_back(id_under);
		}
		if(!check[now]) {
			if(unders.empty()) return -1;
			if(unders.size() == 1) return unders.front();
		}
		assert(nxt_id == int(original_vertex_id.size()));
		original_vertex_id.push_back(-1);
		if(check[now] == 1) {
			original_vertex_id.back() = now;
		}
		foa(c, unders) g.add_edge(c, nxt_id);
		original_to_converted[now] = nxt_id;
		return nxt_id++;
	};
	const int root = 0;
	dfs(dfs, root, -1);
	int ans = 0;
	const int cs = int(chords.size());
	auto ok = [&](int bits) -> bool {
		vector<pair<int, int>> edges;
		set<int> loopvertex;
		vector<int> has_edge(g.size());
		rep(i, cs) {
			if(bits & (1 << i)) {
				int u, v;
				tie(u, v) = chords[i];
				u = original_to_converted[u];
				v = original_to_converted[v];
				edges.emplace_back(u, v);
				has_edge[u]++;
				has_edge[v]++;
				loopvertex.insert(u);
				loopvertex.insert(v);
			}
		}
		enum { ng = -2, nothing = -1 };

		auto connect = [&](auto self, int now, int par) -> int {
			const int &adj_now = has_edge[now];
			if(adj_now > 2) return ng;
			vector<int> unders;
			foa(e, g[now]) {
				if(e.to == par) continue;
				int id = self(self, e.to, now);
				if(id == ng) return ng;
				if(id == nothing) continue;
				if(adj_now == 2) return ng;
				unders.push_back(id);
			}
			if(adj_now + unders.size() > 2) return ng;
			if(adj_now == 2) return nothing;
			if(adj_now) unders.push_back(now);
			if(unders.empty()) return nothing;
			if(unders.size() == 2) {
				edges.emplace_back(unders.front(), unders.back());
				return nothing;
			}
			return unders.front();
		};

		if(connect(connect, root, -1) == ng) return false;
		UF uf_tmp(nxt_id);
		for(auto [u, v] : edges) {
			uf_tmp.unite(u, v);
		}
		return uf_tmp.size(edges.front().first) == (int)loopvertex.size();
	};

	rep(bits, 1, (1 << cs)) {
		if(ok(bits)) {
			ans++;
		}
	}

	return ans;
}

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout << std::fixed << std::setprecision(15);
	srand((unsigned)time(NULL));

	int n, m;
	while(cin >> n >> m && n) {
		cout << solve(n, m) << dl;
	}

	return 0;
}
accuracy: 1
time_ms: 1870
memory_kb: 31196
final_rank: 9

code_snippet: #include <iostream>
#include <numeric>
#include <vector>
#include <tuple>
#include <bitset>

struct UnionFind {
    std::vector<int> par;
    int gnum;

    explicit UnionFind(int n) : par(n, -1), gnum(n) {}

    int find(int v) {
        return (par[v] < 0) ? v : (par[v] = find(par[v]));
    }

    void unite(int u, int v) {
        u = find(u), v = find(v);
        if (u == v) return;

        if (par[u] > par[v]) std::swap(u, v);
        par[u] += par[v];
        par[v] = u;
        --gnum;
    }

    bool same(int u, int v) { return find(u) == find(v); }
    bool ispar(int v) { return par[v] < 0; }
    int size(int v) { return -par[find(v)]; }
};

using namespace std;
using bit = bitset<100020>;

void solve() {
    int n, m;
    cin >> n >> m;

    vector<pair<int, int>> es;
    vector<vector<pair<int, int>>> graph(n);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        --u, --v;

        es.emplace_back(u, v);
        graph[u].emplace_back(v, i);
        graph[v].emplace_back(u, i);
    }

    bit tree;
    {
        vector<bool> visited(n, false);
        auto dfs = [&](auto&& f, int v) -> void {
            visited[v] = true;
            for (auto [u, i] : graph[v]) {
                if (visited[u]) continue;
                tree.set(i);
                f(f, u);
            }
        };
        dfs(dfs, 0);
    }

    vector<bit> bases;
    for (int i = 0; i < m; ++i) {
        if (tree[i]) continue;

        int s, t;
        tie(s, t) = es[i];

        bit basis;
        basis.set(i);

        auto dfs = [&](auto&& f, int v, int p) -> bool {
            if (v == t) return true;

            for (auto [u, j] : graph[v]) {
                if (u == p || !tree[j]) continue;
                if (f(f, u, v)) {
                    basis.set(j);
                    return true;
                }
            }
            return false;
        };
        dfs(dfs, s, -1);

        bases.push_back(basis);
    }

    int k = bases.size();

    vector<bool> need(n, false);
    for (int i = 0; i < m; ++i) {
        if (tree[i]) continue;
        auto [u, v] = es[i];
        need[u] = need[v] = true;
    }

    bit used;
    for (auto basis : bases) used |= basis;

    for (int v = 0; v < n; ++v) {
        int d = 0;
        for (auto [u, i] : graph[v]) {
            if (used[i]) ++d;
        }
        if (d > 2) need[v] = true;
    }

    int nn = accumulate(need.begin(), need.end(), 0);
    vector<int> vid(n, -1);
    {
        int id = 0;
        for (int v = 0; v < n; ++v) {
            if (need[v]) vid[v] = id++;
        }
    }

    vector<pair<int, int>> nes;
    vector<bit> nbases(k);
    {
        vector<bool> visited(n, false);
        for (int s = 0; s < n; ++s) {
            if (!need[s]) continue;

            vector<int> bids;
            auto dfs = [&](auto&& f, int v, int p) -> void {
                if (visited[v]) return;

                if (need[v]) {
                    for (auto bid : bids) nbases[bid].set(nes.size());
                    nes.emplace_back(vid[s], vid[v]);
                    return;
                }

                for (auto [u, j] : graph[v]) {
                    if (u == p || !used[j]) continue;
                    f(f, u, v);
                }
            };

            for (auto [v, i] : graph[s]) {
                if (!used[i]) continue;

                bids.clear();
                for (int bid = 0; bid < k; ++bid) {
                    if (bases[bid][i]) bids.push_back(bid);
                }
                dfs(dfs, v, s);
            }

            visited[s] = true;
        }
    }

    int ans = 0;
    for (int b = 1; b < (1 << k); ++b) {
        bit marked;
        for (int i = 0; i < k; ++i) {
            if ((b >> i) & 1) marked ^= nbases[i];
        }

        int cnt = marked.count();
        UnionFind uf(nn);
        for (int i = 0; i < m; ++i) {
            if (marked[i]) {
                auto [u, v] = nes[i];
                uf.unite(u, v);
            }
        }

        if (uf.gnum + cnt - nn == 1) ++ans;
    }

    cout << ans << "\n";
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    solve();

    return 0;
}
accuracy: 1
time_ms: 3330
memory_kb: 19680
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;
int N;
vector<pair<int,int>> E;
vector<int> G[MAX],G2[MAX];
bool seen[MAX];
vector<int> use;
bool imp[MAX];
int depth[MAX],par[MAX],nex[MAX];

void make(int u,int p){
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        if(seen[to]){
            if(depth[to]<depth[u]){
                use.push_back(u);
                use.push_back(to);
                use.push_back(par[u]);
                use.push_back(nex[to]);
                E.push_back(mp(u,to));
            }
        }else{
            G2[u].push_back(to);
            depth[to]=depth[u]+1;
            nex[u]=to;
            make(to,u);
        }
    }
}

vector<int> GG[MAX];

void DFS(int u,int p,int ro){
    if(u!=ro&&imp[u]){
        GG[ro].push_back(u);
        return;
    }
    for(int to:G2[u]){
        if(to==p) continue;
        DFS(to,u,ro);
    }
}

void make2(int u,int p){
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        depth[to]=depth[u]+1;
        make2(to,u);
    }
}

//Union Find

struct UF{
    int n;
    vector<int> par,size;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};

const int MAX_LOG=20;
int parr[MAX_LOG][MAX],dep[MAX];

void init(int u){
    for(int i=0;i<N;i++){
        dep[i]=INF;
        for(int j=0;j<20;j++){
            parr[j][i]=-1;
        }
    }
    queue<int> Q;
    Q.push(u);
    dep[u]=0;
    while(!Q.empty()){
        int a=Q.front();
        Q.pop();
        for(int to:G2[a]){
            if(chmin(dep[to],dep[a]+1)){
                parr[0][to]=a;
                Q.push(to);
            }
        }
    }
    
    for(int k=0;k+1<MAX_LOG;k++){
        for(int i=0;i<N;i++){
            if(parr[k][i]<0) parr[k+1][i]=-1;
            else parr[k+1][i]=parr[k][parr[k][i]];
        }
    }
}

int lca(int u,int v){
    if(dep[u]>dep[v]) swap(u,v);
    for(int i=0;i<20;i++){
        if(((dep[v]-dep[u])>>i)&1) v=parr[i][v];
    }
    if(u==v) return u;
    
    for(int i=19;i>=0;i--){
        if(parr[i][u]!=parr[i][v]){
            u = parr[i][u];
            v = parr[i][v];
        }
    }
    return parr[0][u];
}


int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int M;cin>>N>>M;
    if(M==N-1){
        cout<<0<<endl;
        return 0;
    }
    for(int i=0;i<M;i++){
        int a,b;cin>>a>>b;
        a--;b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    
    make(0,-1);
    
    use.push_back(0);
    
    init(0);
    
    vector<int> X;
    for(int i=0;i<si(use);i++){
        for(int j=i+1;j<si(use);j++){
            X.push_back(lca(use[i],use[j]));
        }
    }
    
    for(int x:X) use.push_back(x);
    
    sort(all(use));
    use.erase(unique(all(use)),use.end());
    
    for(int a:use) imp[a]=true;
    
    for(int a:use){
        DFS(a,-1,a);
    }
    
    for(int i=0;i<N;i++) G[i].clear();
    
    memset(depth,0,sizeof(depth));
    memset(par,-1,sizeof(par));
    
    auto f=[&](int u){
        return (int)(lower_bound(all(use),u)-use.begin());
    };
    int cnt=0;
    for(int i=0;i<N;i++){
        sort(all(GG[i]));
        GG[i].erase(unique(all(GG[i])),GG[i].end());
        for(int to:GG[i]){
            int a=i,b=to;
            a=f(a);
            b=f(b);
            G[a].push_back(b);
            cnt++;
        }
    }
    for(auto &e:E){
        e.fi=f(e.fi);
        e.se=f(e.se);
    }
    
    memset(seen,0,sizeof(seen));
    make2(0,-1);
    
    int ans=0;
    
    for(int bit=1;bit<(1<<si(E));bit++){
        UF uf;uf.init(si(use));
        set<pair<int,int>> SE;
        vector<int> deg(si(use));
        for(int i=0;i<si(E);i++){
            if(!(bit&(1<<i))) continue;
            int a=E[i].fi,b=E[i].se;
            while(a!=b){
                if(depth[a]>depth[b]) swap(a,b);
                if(SE.count(mp(par[b],b))) SE.erase(mp(par[b],b));
                else SE.insert(mp(par[b],b));
                b=par[b];
            }
            a=E[i].fi,b=E[i].se;
            if(depth[a]>depth[b]) swap(a,b);
            if(SE.count(mp(a,b))) SE.erase(mp(a,b));
            else SE.insert(mp(a,b));
        }
        
        for(auto e:SE){
            deg[e.fi]++;
            deg[e.se]++;
            uf.unite(e.fi,e.se);
        }
        
        bool ok=true;
        
        int cn=0;
        for(int i=0;i<si(use);i++){
            ok&=((deg[i]==0||deg[i]==2));
            if(!ok) break;
            if(uf.root(i)!=i) continue;
            if(uf.size[i]>=2) cn++;
        }
        
        ok&=(cn<=1);
        
        if(ok) ans++;
    }
    
    cout<<ans<<endl;
    
}
accuracy: 1
time_ms: 970
memory_kb: 32504
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;
int N;
vector<pair<int,int>> E;
vector<int> G[MAX],G2[MAX];
bool seen[MAX];
vector<int> use;
bool imp[MAX];
int depth[MAX],par[MAX],nex[MAX];

void make(int u,int p){
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        if(seen[to]){
            if(depth[to]<depth[u]){
                use.push_back(u);
                use.push_back(to);
                use.push_back(par[u]);
                use.push_back(nex[to]);
                E.push_back(mp(u,to));
            }
        }else{
            G2[u].push_back(to);
            depth[to]=depth[u]+1;
            nex[u]=to;
            make(to,u);
        }
    }
}

vector<int> GG[MAX];

void DFS(int u,int p,int ro){
    if(u!=ro&&imp[u]){
        GG[ro].push_back(u);
        return;
    }
    for(int to:G2[u]){
        if(to==p) continue;
        DFS(to,u,ro);
    }
}

void make2(int u,int p){
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        depth[to]=depth[u]+1;
        make2(to,u);
    }
}

//Union Find

struct UF{
    int n;
    vector<int> par,size;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};

const int MAX_LOG=20;
int parr[MAX_LOG][MAX],dep[MAX];

void init(int u){
    for(int i=0;i<N;i++){
        dep[i]=INF;
        for(int j=0;j<20;j++){
            parr[j][i]=-1;
        }
    }
    queue<int> Q;
    Q.push(u);
    dep[u]=0;
    while(!Q.empty()){
        int a=Q.front();
        Q.pop();
        for(int to:G2[a]){
            if(chmin(dep[to],dep[a]+1)){
                parr[0][to]=a;
                Q.push(to);
            }
        }
    }
    
    for(int k=0;k+1<MAX_LOG;k++){
        for(int i=0;i<N;i++){
            if(parr[k][i]<0) parr[k+1][i]=-1;
            else parr[k+1][i]=parr[k][parr[k][i]];
        }
    }
}

int lca(int u,int v){
    if(dep[u]>dep[v]) swap(u,v);
    for(int i=0;i<20;i++){
        if(((dep[v]-dep[u])>>i)&1) v=parr[i][v];
    }
    if(u==v) return u;
    
    for(int i=19;i>=0;i--){
        if(parr[i][u]!=parr[i][v]){
            u = parr[i][u];
            v = parr[i][v];
        }
    }
    return parr[0][u];
}


int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int M;cin>>N>>M;
    if(M==N-1){
        cout<<0<<endl;
        return 0;
    }
    for(int i=0;i<M;i++){
        int a,b;cin>>a>>b;
        a--;b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    
    make(0,-1);
    
    use.push_back(0);
    
    init(0);
    
    vector<int> X;
    for(int i=0;i<si(use);i++){
        for(int j=i+1;j<si(use);j++){
            X.push_back(lca(use[i],use[j]));
        }
    }
    
    for(int x:X) use.push_back(x);
    
    sort(all(use));
    use.erase(unique(all(use)),use.end());
    
    for(int a:use) imp[a]=true;
    
    for(int a:use){
        DFS(a,-1,a);
    }
    
    for(int i=0;i<N;i++) G[i].clear();
    
    memset(depth,0,sizeof(depth));
    memset(par,-1,sizeof(par));
    
    auto f=[&](int u){
        return (int)(lower_bound(all(use),u)-use.begin());
    };
    int cnt=0;
    for(int i=0;i<N;i++){
        sort(all(GG[i]));
        GG[i].erase(unique(all(GG[i])),GG[i].end());
        for(int to:GG[i]){
            int a=i,b=to;
            a=f(a);
            b=f(b);
            G[a].push_back(b);
            cnt++;
        }
    }
    for(auto &e:E){
        e.fi=f(e.fi);
        e.se=f(e.se);
    }
    
    memset(seen,0,sizeof(seen));
    make2(0,-1);
    
    int ans=0;
    
    for(int bit=1;bit<(1<<si(E));bit++){
        UF uf;uf.init(si(use));
        set<pair<int,int>> SE;
        vector<int> deg(si(use));
        for(int i=0;i<si(E);i++){
            if(!(bit&(1<<i))) continue;
            int a=E[i].fi,b=E[i].se;
            while(a!=b){
                if(depth[a]>depth[b]) swap(a,b);
                if(SE.count(mp(par[b],b))) SE.erase(mp(par[b],b));
                else SE.insert(mp(par[b],b));
                b=par[b];
            }
            a=E[i].fi,b=E[i].se;
            if(depth[a]>depth[b]) swap(a,b);
            if(SE.count(mp(a,b))) SE.erase(mp(a,b));
            else SE.insert(mp(a,b));
        }
        
        for(auto e:SE){
            deg[e.fi]++;
            deg[e.se]++;
            uf.unite(e.fi,e.se);
        }
        
        bool ok=true;
        
        int cn=0;
        for(int i=0;i<si(use);i++){
            ok&=((deg[i]==0||deg[i]==2));
            if(!ok) break;
            if(uf.root(i)!=i) continue;
            if(uf.size[i]>=2) cn++;
        }
        
        ok&=(cn<=1);
        
        if(ok) ans++;
    }
    
    cout<<ans<<endl;
    
}
accuracy: 1
time_ms: 970
memory_kb: 32608
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;
int N;
vector<pair<int,int>> E;
vector<int> G[MAX],G2[MAX];
bool seen[MAX];
vector<int> use;
bool imp[MAX];
int depth[MAX],par[MAX],nex[MAX];

void make(int u,int p){
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        if(seen[to]){
            if(depth[to]<depth[u]){
                use.push_back(u);
                use.push_back(to);
                //use.push_back(par[u]);
               // use.push_back(nex[to]);
                E.push_back(mp(u,to));
            }
        }else{
            G2[u].push_back(to);
            depth[to]=depth[u]+1;
            nex[u]=to;
            make(to,u);
        }
    }
}

vector<int> GG[MAX];

void DFS(int u,int p,int ro){
    if(u!=ro&&imp[u]){
        GG[ro].push_back(u);
        //GG[u].push_back(ro);
        return;
    }
    for(int to:G2[u]){
        if(to==p) continue;
        DFS(to,u,ro);
    }
}

void make2(int u,int p){
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        depth[to]=depth[u]+1;
        make2(to,u);
    }
}

//Union Find

struct UF{
    int n;
    vector<int> par,size;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};

const int MAX_LOG=20;
int parr[MAX_LOG][MAX],dep[MAX];

void init(int u){
    for(int i=0;i<N;i++){
        dep[i]=INF;
        for(int j=0;j<20;j++){
            parr[j][i]=-1;
        }
    }
    queue<int> Q;
    Q.push(u);
    dep[u]=0;
    while(!Q.empty()){
        int a=Q.front();
        Q.pop();
        for(int to:G2[a]){
            if(chmin(dep[to],dep[a]+1)){
                parr[0][to]=a;
                Q.push(to);
            }
        }
    }
    
    for(int k=0;k+1<MAX_LOG;k++){
        for(int i=0;i<N;i++){
            if(parr[k][i]<0) parr[k+1][i]=-1;
            else parr[k+1][i]=parr[k][parr[k][i]];
        }
    }
}

int lca(int u,int v){
    if(dep[u]>dep[v]) swap(u,v);
    for(int i=0;i<20;i++){
        if(((dep[v]-dep[u])>>i)&1) v=parr[i][v];
    }
    if(u==v) return u;
    
    for(int i=19;i>=0;i--){
        if(parr[i][u]!=parr[i][v]){
            u = parr[i][u];
            v = parr[i][v];
        }
    }
    return parr[0][u];
}


int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int M;cin>>N>>M;
    if(M==N-1){
        cout<<0<<endl;
        return 0;
    }
    for(int i=0;i<M;i++){
        int a,b;cin>>a>>b;
        a--;b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    
    make(0,-1);
    
    use.push_back(0);
    
    init(0);
    
    vector<int> X;
    for(int i=0;i<si(use);i++){
        for(int j=i+1;j<si(use);j++){
            X.push_back(lca(use[i],use[j]));
        }
    }
    
    for(int x:X) use.push_back(x);
    
    sort(all(use));
    use.erase(unique(all(use)),use.end());
    
    //cout<<si(use)<<endl;
    
    for(int a:use) imp[a]=true;
    
    for(int a:use){
        DFS(a,-1,a);
        //cout<<a<<endl;
    }
    
    for(int i=0;i<N;i++) G[i].clear();
    
    memset(depth,0,sizeof(depth));
    memset(par,-1,sizeof(par));
    
    auto f=[&](int u){
        return (int)(lower_bound(all(use),u)-use.begin());
    };
    int cnt=0;
    for(int i=0;i<N;i++){
        sort(all(GG[i]));
        GG[i].erase(unique(all(GG[i])),GG[i].end());
        for(int to:GG[i]){
            int a=i,b=to;
            //cout<<a<<" "<<b<<" ";
            a=f(a);
            b=f(b);
            G[a].push_back(b);
            cnt++;
            //G[b].push_back(a);
            //cout<<a<<" "<<b<<"!"<<endl;
            //cout<<a+1<<" "<<b+1<<endl;
        }
    }
    //cout<<si(use)<<" "<<cnt<<endl;
    for(auto &e:E){
        e.fi=f(e.fi);
        e.se=f(e.se);
        //cout<<e.fi+1<<" "<<e.se+1<<endl;
    }
    
    memset(seen,0,sizeof(seen));
    make2(0,-1);
    
    int ans=0;
    
    //for(auto a:E) cout<<depth[a.fi]<<" "<<depth[a.se]<<endl;
    
    for(int bit=1;bit<(1<<si(E));bit++){
        UF uf;uf.init(si(use));
        set<pair<int,int>> SE;
        vector<int> deg(si(use));
        for(int i=0;i<si(E);i++){
            if(!(bit&(1<<i))) continue;
            int a=E[i].fi,b=E[i].se;
            while(a!=b){
                //cout<<a<<" "<<b<<endl;
                if(depth[a]>depth[b]) swap(a,b);
                if(SE.count(mp(par[b],b))) SE.erase(mp(par[b],b));
                else SE.insert(mp(par[b],b));
                b=par[b];
            }
            a=E[i].fi,b=E[i].se;
            //assert(abs(depth[a]-depth[b])>=2);
            if(depth[a]>depth[b]) swap(a,b);
            if(SE.count(mp(a,b))) SE.erase(mp(a,b));
            else SE.insert(mp(a,b));
        }
        
        for(auto e:SE){
            deg[e.fi]++;
            deg[e.se]++;
            uf.unite(e.fi,e.se);
        }
        
        bool ok=true;
        
        int cn=0;
        for(int i=0;i<si(use);i++){
            ok&=((deg[i]==0||deg[i]==2));
            if(!ok) break;
            if(uf.root(i)!=i) continue;
            if(uf.size[i]>=2) cn++;
        }
        
        ok&=(cn<=1);
        
        if(ok) ans++;
        
        //if(bit%100==0) cout<<bit<<" "<<ans<<endl;
    }
    
    //cout<<si(E)<<" "<<si(use)<<endl;
    
    cout<<ans<<endl;
    
}
accuracy: 0.3333333333333333
time_ms: 620
memory_kb: 31440
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;
int N;
vector<pair<int,int>> E;
vector<int> G[MAX],G2[MAX];
bool seen[MAX];
vector<int> use;
bool imp[MAX];
int depth[MAX],par[MAX],nex[MAX];

void make(int u,int p){
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        if(seen[to]){
            if(depth[to]<depth[u]){
                use.push_back(u);
                use.push_back(to);
                use.push_back(par[u]);
                use.push_back(nex[to]);
                E.push_back(mp(u,to));
            }
        }else{
            G2[u].push_back(to);
            depth[to]=depth[u]+1;
            nex[u]=to;
            make(to,u);
        }
    }
}

vector<int> GG[MAX];

void DFS(int u,int p,int ro){
    if(u!=ro&&imp[u]){
        GG[ro].push_back(u);
        //GG[u].push_back(ro);
        return;
    }
    for(int to:G2[u]){
        if(to==p) continue;
        DFS(to,u,ro);
    }
}

void make2(int u,int p){
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        depth[to]=depth[u]+1;
        make2(to,u);
    }
}

//Union Find

struct UF{
    int n;
    vector<int> par,size;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};

const int MAX_LOG=20;
int parr[MAX_LOG][MAX],dep[MAX];

void init(int u){
    for(int i=0;i<N;i++){
        dep[i]=INF;
        for(int j=0;j<20;j++){
            parr[j][i]=-1;
        }
    }
    queue<int> Q;
    Q.push(u);
    dep[u]=0;
    while(!Q.empty()){
        int a=Q.front();
        Q.pop();
        for(int to:G2[a]){
            if(chmin(dep[to],dep[a]+1)){
                parr[0][to]=a;
                Q.push(to);
            }
        }
    }
    
    for(int k=0;k+1<MAX_LOG;k++){
        for(int i=0;i<N;i++){
            if(parr[k][i]<0) parr[k+1][i]=-1;
            else parr[k+1][i]=parr[k][parr[k][i]];
        }
    }
}

int lca(int u,int v){
    if(dep[u]>dep[v]) swap(u,v);
    for(int i=0;i<20;i++){
        if(((dep[v]-dep[u])>>i)&1) v=parr[i][v];
    }
    if(u==v) return u;
    
    for(int i=19;i>=0;i--){
        if(parr[i][u]!=parr[i][v]){
            u = parr[i][u];
            v = parr[i][v];
        }
    }
    return parr[0][u];
}


int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int M;cin>>N>>M;
    if(M==N-1){
        cout<<0<<endl;
        return 0;
    }
    for(int i=0;i<M;i++){
        int a,b;cin>>a>>b;
        a--;b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    
    make(0,-1);
    
    use.push_back(0);
    
    init(0);
    
    vector<int> X;
    for(int i=0;i<si(use);i++){
        for(int j=i+1;j<si(use);j++){
            X.push_back(lca(use[i],use[j]));
        }
    }
    
    for(int x:X) use.push_back(x);
    
    sort(all(use));
    use.erase(unique(all(use)),use.end());
    
    //cout<<si(use)<<endl;
    
    for(int a:use) imp[a]=true;
    
    for(int a:use){
        DFS(a,-1,a);
        //cout<<a<<endl;
    }
    
    for(int i=0;i<N;i++) G[i].clear();
    
    memset(depth,0,sizeof(depth));
    memset(par,-1,sizeof(par));
    
    auto f=[&](int u){
        return (int)(lower_bound(all(use),u)-use.begin());
    };
    int cnt=0;
    for(int i=0;i<N;i++){
        sort(all(GG[i]));
        GG[i].erase(unique(all(GG[i])),GG[i].end());
        for(int to:GG[i]){
            int a=i,b=to;
            //cout<<a<<" "<<b<<" ";
            a=f(a);
            b=f(b);
            G[a].push_back(b);
            cnt++;
            //G[b].push_back(a);
            //cout<<a<<" "<<b<<"!"<<endl;
            //cout<<a+1<<" "<<b+1<<endl;
        }
    }
    //cout<<si(use)<<" "<<cnt<<endl;
    for(auto &e:E){
        e.fi=f(e.fi);
        e.se=f(e.se);
        //cout<<e.fi+1<<" "<<e.se+1<<endl;
    }
    
    memset(seen,0,sizeof(seen));
    make2(0,-1);
    
    int ans=0;
    
    //for(auto a:E) cout<<depth[a.fi]<<" "<<depth[a.se]<<endl;
    
    for(int bit=1;bit<(1<<si(E));bit++){
        UF uf;uf.init(si(use));
        set<pair<int,int>> SE;
        vector<int> deg(si(use));
        for(int i=0;i<si(E);i++){
            if(!(bit&(1<<i))) continue;
            int a=E[i].fi,b=E[i].se;
            while(a!=b){
                //cout<<a<<" "<<b<<endl;
                if(depth[a]>depth[b]) swap(a,b);
                if(SE.count(mp(par[b],b))) SE.erase(mp(par[b],b));
                else SE.insert(mp(par[b],b));
                b=par[b];
            }
            a=E[i].fi,b=E[i].se;
            //assert(abs(depth[a]-depth[b])>=2);
            if(depth[a]>depth[b]) swap(a,b);
            if(SE.count(mp(a,b))) SE.erase(mp(a,b));
            else SE.insert(mp(a,b));
        }
        
        for(auto e:SE){
            deg[e.fi]++;
            deg[e.se]++;
            uf.unite(e.fi,e.se);
        }
        
        bool ok=true;
        
        int cn=0;
        for(int i=0;i<si(use);i++){
            ok&=((deg[i]==0||deg[i]==2));
            if(!ok) break;
            if(uf.root(i)!=i) continue;
            if(uf.size[i]>=2) cn++;
        }
        
        ok&=(cn<=1);
        
        if(ok) ans++;
        
        //if(bit%100==0) cout<<bit<<" "<<ans<<endl;
    }
    
    //cout<<si(E)<<" "<<si(use)<<endl;
    
    cout<<ans<<endl;
    
}
accuracy: 1
time_ms: 970
memory_kb: 32536
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;

vector<pair<int,int>> E;
vector<int> G[MAX],G2[MAX];
bool seen[MAX];
vector<int> use;
bool imp[MAX];
int depth[MAX],par[MAX],nex[MAX];

void make(int u,int p){
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        if(seen[to]){
            if(depth[to]<depth[u]){
                use.push_back(u);
                use.push_back(to);
                use.push_back(par[u]);
                use.push_back(nex[to]);
                E.push_back(mp(u,to));
            }
        }else{
            G2[u].push_back(to);
            depth[to]=depth[u]+1;
            nex[u]=to;
            make(to,u);
        }
    }
}

vector<int> GG[MAX];

void DFS(int u,int p,int ro){
    if(u!=ro&&imp[u]){
        GG[ro].push_back(u);
        //GG[u].push_back(ro);
        return;
    }
    for(int to:G2[u]){
        if(to==p) continue;
        DFS(to,u,ro);
    }
}

void make2(int u,int p){
    if(seen[u]) return;
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        depth[to]=depth[u]+1;
        make2(to,u);
    }
}

//Union Find

struct UF{
    int n;
    vector<int> par,size;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};


int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int N,M;cin>>N>>M;
    if(M==N-1){
        cout<<0<<endl;
        return 0;
    }
    for(int i=0;i<M;i++){
        int a,b;cin>>a>>b;
        a--;b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    
    make(0,-1);
    use.push_back(0);
    
    sort(all(use));
    use.erase(unique(all(use)),use.end());
    
    for(int a:use) imp[a]=true;
    
    for(int a:use){
        DFS(a,-1,a);
        //cout<<a<<endl;
    }
    
    for(int i=0;i<N;i++) G[i].clear();
    
    memset(depth,0,sizeof(depth));
    memset(par,-1,sizeof(par));
    
    auto f=[&](int u){
        return (int)(lower_bound(all(use),u)-use.begin());
    };
    int cnt=0;
    for(int i=0;i<N;i++){
        sort(all(GG[i]));
        GG[i].erase(unique(all(GG[i])),GG[i].end());
        for(int to:GG[i]){
            int a=i,b=to;
            //cout<<a<<" "<<b<<" ";
            a=f(a);
            b=f(b);
            G[a].push_back(b);
            cnt++;
            //G[b].push_back(a);
            //cout<<a<<" "<<b<<"!"<<endl;
        }
    }
    //cout<<si(use)<<" "<<cnt<<endl;
    for(auto &e:E){
        e.fi=f(e.fi);
        e.se=f(e.se);
        //cout<<e.fi<<" "<<e.se<<endl;
    }
    
    memset(seen,0,sizeof(seen));
    make2(0,-1);
    
    int ans=0;
    
    //for(auto a:E) cout<<depth[a.fi]<<" "<<depth[a.se]<<endl;
    
    for(int bit=1;bit<(1<<si(E));bit++){
        UF uf;uf.init(si(use));
        set<pair<int,int>> SE;
        vector<int> deg(si(use));
        for(int i=0;i<si(E);i++){
            if(!(bit&(1<<i))) continue;
            int a=E[i].fi,b=E[i].se;
            while(a!=b){
                //cout<<a<<" "<<b<<endl;
                if(depth[a]>depth[b]) swap(a,b);
                if(SE.count(mp(par[b],b))) SE.erase(mp(par[b],b));
                else SE.insert(mp(par[b],b));
                b=par[b];
            }
            a=E[i].fi,b=E[i].se;
            //assert(abs(depth[a]-depth[b])>=2);
            if(depth[a]>depth[b]) swap(a,b);
            if(SE.count(mp(a,b))) SE.erase(mp(a,b));
            else SE.insert(mp(a,b));
        }
        
        for(auto e:SE){
            deg[e.fi]++;
            deg[e.se]++;
            uf.unite(e.fi,e.se);
        }
        
        bool ok=true;
        
        int cn=0;
        for(int i=0;i<si(use);i++){
            ok&=((deg[i]==0||deg[i]==2));
            if(uf.root(i)!=i) continue;
            if(uf.size[i]>=2) cn++;
        }
        
        ok&=(cn<=1);
        
        if(ok) ans++;
    }
    
    //cout<<si(E)<<" "<<si(use)<<endl;
    
    cout<<ans<<endl;
    
}
accuracy: 0.07407407407407407
time_ms: 300
memory_kb: 17068
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;

vector<pair<int,int>> E;
vector<int> G[MAX],G2[MAX];
bool seen[MAX];
vector<int> use;
bool imp[MAX];
int depth[MAX],par[MAX];

void make(int u,int p){
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        if(seen[to]){
            if(depth[to]<depth[u]){
                use.push_back(u);
                use.push_back(to);
                use.push_back(par[u]);
                E.push_back(mp(u,to));
            }
        }else{
            G2[u].push_back(to);
            depth[to]=depth[u]+1;
            make(to,u);
        }
    }
}

vector<int> GG[MAX];

void DFS(int u,int p,int ro){
    if(u!=ro&&imp[u]){
        GG[ro].push_back(u);
        //GG[u].push_back(ro);
        return;
    }
    for(int to:G2[u]){
        if(to==p) continue;
        DFS(to,u,ro);
    }
}

void make2(int u,int p){
    if(seen[u]) return;
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        depth[to]=depth[u]+1;
        make2(to,u);
    }
}

//Union Find

struct UF{
    int n;
    vector<int> par,size;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};


int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int N,M;cin>>N>>M;
    if(M==N-1){
        cout<<0<<endl;
        return 0;
    }
    for(int i=0;i<M;i++){
        int a,b;cin>>a>>b;
        a--;b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    
    make(0,-1);
    use.push_back(0);
    
    sort(all(use));
    use.erase(unique(all(use)),use.end());
    
    for(int a:use) imp[a]=true;
    
    for(int a:use){
        DFS(a,-1,a);
        //cout<<a<<endl;
    }
    
    for(int i=0;i<N;i++) G[i].clear();
    
    memset(depth,0,sizeof(depth));
    memset(par,-1,sizeof(par));
    
    auto f=[&](int u){
        return (int)(lower_bound(all(use),u)-use.begin());
    };
    int cnt=0;
    for(int i=0;i<N;i++){
        sort(all(GG[i]));
        GG[i].erase(unique(all(GG[i])),GG[i].end());
        for(int to:GG[i]){
            int a=i,b=to;
            //cout<<a<<" "<<b<<" ";
            a=f(a);
            b=f(b);
            G[a].push_back(b);
            cnt++;
            //G[b].push_back(a);
            //cout<<a<<" "<<b<<"!"<<endl;
        }
    }
    //cout<<si(use)<<" "<<cnt<<endl;
    for(auto &e:E){
        e.fi=f(e.fi);
        e.se=f(e.se);
        //cout<<e.fi<<" "<<e.se<<endl;
    }
    
    memset(seen,0,sizeof(seen));
    make2(0,-1);
    
    int ans=0;
    
    //for(auto a:E) cout<<depth[a.fi]<<" "<<depth[a.se]<<endl;
    
    for(int bit=1;bit<(1<<si(E));bit++){
        UF uf;uf.init(si(use));
        set<pair<int,int>> SE;
        vector<int> deg(si(use));
        for(int i=0;i<si(E);i++){
            if(!(bit&(1<<i))) continue;
            int a=E[i].fi,b=E[i].se;
            while(a!=b){
                //cout<<a<<" "<<b<<endl;
                if(depth[a]>depth[b]) swap(a,b);
                if(SE.count(mp(par[b],b))) SE.erase(mp(par[b],b));
                else SE.insert(mp(par[b],b));
                b=par[b];
            }
            a=E[i].fi,b=E[i].se;
            //assert(abs(depth[a]-depth[b])>=2);
            if(depth[a]>depth[b]) swap(a,b);
            if(SE.count(mp(a,b))) SE.erase(mp(a,b));
            else SE.insert(mp(a,b));
        }
        
        for(auto e:SE){
            deg[e.fi]++;
            deg[e.se]++;
            uf.unite(e.fi,e.se);
        }
        
        bool ok=true;
        
        int cn=0;
        for(int i=0;i<si(use);i++){
            ok&=((deg[i]==0||deg[i]==2));
            if(uf.root(i)!=i) continue;
            if(uf.size[i]>=2) cn++;
        }
        
        ok&=(cn<=1);
        
        if(ok) ans++;
    }
    
    //cout<<si(E)<<" "<<si(use)<<endl;
    
    cout<<ans<<endl;
    
}
accuracy: 0.07407407407407407
time_ms: 190
memory_kb: 16576
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;

vector<pair<int,int>> E;
vector<int> G[MAX],G2[MAX];
bool seen[MAX];
vector<int> use;
bool imp[MAX];
int depth[MAX],par[MAX];

void make(int u,int p){
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        if(seen[to]){
            if(depth[to]<depth[u]){
                use.push_back(u);
                use.push_back(to);
                use.push_back(par[u]);
                E.push_back(mp(u,to));
            }
        }else{
            G2[u].push_back(to);
            G2[to].push_back(u);
            depth[to]=depth[u]+1;
            make(to,u);
        }
    }
}

vector<int> GG[MAX];

void DFS(int u,int p,int ro){
    if(u!=ro&&imp[u]){
        GG[ro].push_back(u);
        GG[u].push_back(ro);
        return;
    }
    for(int to:G2[u]){
        if(to==p) continue;
        DFS(to,u,ro);
    }
}

void make2(int u,int p){
    if(seen[u]) return;
    seen[u]=true;
    par[u]=p;
    for(int to:G[u]){
        if(to==p) continue;
        depth[to]=depth[u]+1;
        make2(to,u);
    }
}

//Union Find

struct UF{
    int n;
    vector<int> par,size;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};


int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int N,M;cin>>N>>M;
    if(M==N-1){
        cout<<0<<endl;
        return 0;
    }
    for(int i=0;i<M;i++){
        int a,b;cin>>a>>b;
        a--;b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    
    make(0,-1);
    use.push_back(0);
    
    sort(all(use));
    use.erase(unique(all(use)),use.end());
    
    for(int a:use) imp[a]=true;
    
    for(int a:use){
        DFS(a,-1,a);
        //cout<<a<<endl;
    }
    
    for(int i=0;i<N;i++) G[i].clear();
    
    memset(depth,0,sizeof(depth));
    memset(par,-1,sizeof(par));
    
    auto f=[&](int u){
        return (int)(lower_bound(all(use),u)-use.begin());
    };
    
    for(int i=0;i<N;i++){
        sort(all(GG[i]));
        GG[i].erase(unique(all(GG[i])),GG[i].end());
        for(int to:GG[i]){
            int a=i,b=to;
            //cout<<a<<" "<<b<<" ";
            a=f(a);
            b=f(b);
            G[a].push_back(b);
            //G[b].push_back(a);
            //cout<<a<<" "<<b<<"!"<<endl;
        }
    }
    
    for(auto &e:E){
        e.fi=f(e.fi);
        e.se=f(e.se);
        //cout<<e.fi<<" "<<e.se<<endl;
    }
    
    memset(seen,0,sizeof(seen));
    make2(0,-1);
    
    int ans=0;
    
    //for(auto a:E) cout<<depth[a.fi]<<" "<<depth[a.se]<<endl;
    
    for(int bit=1;bit<(1<<si(E));bit++){
        UF uf;uf.init(si(use));
        set<pair<int,int>> SE;
        vector<int> deg(si(use));
        for(int i=0;i<si(E);i++){
            if(!(bit&(1<<i))) continue;
            int a=E[i].fi,b=E[i].se;
            while(a!=b){
                //cout<<a<<" "<<b<<endl;
                if(depth[a]>depth[b]) swap(a,b);
                if(SE.count(mp(par[b],b))) SE.erase(mp(par[b],b));
                else SE.insert(mp(par[b],b));
                b=par[b];
            }
            a=E[i].fi,b=E[i].se;
            if(depth[a]>depth[b]) swap(a,b);
            if(SE.count(mp(a,b))) SE.erase(mp(a,b));
            else SE.insert(mp(a,b));
        }
        
        for(auto e:SE){
            deg[e.fi]++;
            deg[e.se]++;
            uf.unite(e.fi,e.se);
        }
        
        bool ok=true;
        
        int cn=0;
        for(int i=0;i<si(use);i++){
            ok&=((deg[i]==0||deg[i]==2));
            if(uf.root(i)!=i) continue;
            if(uf.size[i]>=2) cn++;
        }
        
        ok&=(cn<=1);
        
        if(ok) ans++;
    }
    
    //cout<<si(E)<<" "<<si(use)<<endl;
    
    cout<<ans<<endl;
    
}
accuracy: 0.07407407407407407
time_ms: 290
memory_kb: 17856
final_rank: 18