Language: C++

#pragma GCC optimize("Ofast")
#pragma GCC target("avx")
#include <bits/stdc++.h>
using namespace std;

#define INIT std::cin.tie(0);std::ios::sync_with_stdio(false);
#define ALL(c) (c).begin(), (c).end()
#define CALL(c) (c).cbegin(), (c).cend()
#define RALL(c) (c).rbegin(), (c).rend()
#define CRALL(c) (c).crbegin(), (c).crend()
#define REP(i, n) for (int i = 0; i < static_cast<int>(n); i++)
#define FOR(i, s, n) for (int i = s; i < static_cast<int>(n); i++)
#define ASC(t) [](t& x, t& y){ return x < y; }
#define DESC(t) [](t& x, t& y){ return x > y; }
#define PSORT(s,p,e) partial_sort((s), next((s), (p)), (e))
#define VIEW(v,t) for_each((v).begin(), (v).end(), [](t& a) { cout << a << " "; }); cout << endl;

#define IN(a, x, b) (a<=x && x<b)
template<class T> inline T CHMAX(T& x, const T y){return x=(x<y)?y:x;}
template<class T> inline T CHMIN(T& x, const T y){return x=(x>y)?y:x;}
#define OUT(dist) std::cout<<(dist);
#define WS std::cout<<" ";
#define NL std::cout<<"\n"

using PII = pair<int, int>;
using PLL = pair<long long, long long>;
using LL = long long;
using ULL = unsigned long long;
template<class T> using V = vector<T>;
template<class T> using V2 = vector<vector<T>>;
template<class T, int W=255> using A = array<T, W>;
template<class T, int W=255, int H=255> using A2 = array<array<T, W>, W>;


template<int N=1000001>
class UnionFindTree {
public:
  const LL len = N;
  LL cnt;
  A<LL, N> uftq{};
  A<LL, N> s{};
  A<LL, N> rank{};

  UnionFindTree(LL n) : cnt(n) {
    FOR(i,0,n) {
        uftq[i] = i;
        s[i] = 1;
        rank[i] = 1;
    }
  }
  LL find(LL x) {
      LL xParent = uftq[x];
      V<LL> v;
      while(xParent != uftq[xParent]) {
          v.push_back(xParent);
          xParent = uftq[xParent];
      }
      REP(i, v.size()) {
          uftq[v[i]] = xParent;
      }
      return xParent;
  }
  LL size(LL idx) {
      return s[find(idx)];
  }
  LL count() {
      return cnt;
  }
  bool unite(LL x, LL y) {
      LL xRoot = find(x);
      LL yRoot = find(y);
      if(xRoot == yRoot) return false;
      if(rank[xRoot] > rank[yRoot])
          std::swap(xRoot, yRoot);
      if(rank[xRoot] == rank[yRoot])
          rank[yRoot] += 1 + rank[yRoot] - rank[xRoot];
      s[yRoot] = s[xRoot] + s[yRoot];
      s[xRoot] = 0;
      uftq[xRoot] = yRoot;
      cnt--;
      return true;
  }
};

int main(){
    INIT;
    int n, m;
    cin >> n >> m;
    V<PII> e;
    REP(i,m) {
        int x,y; cin >> x >> y; e.push_back(PII(x-1,y-1));
    }
    V<UnionFindTree<51>> uft;
    uft.resize(m, UnionFindTree<51>{m});

    int ans = 0;
    REP(i,m) {
        REP(j,m) {
            if(i == j) continue;
            uft[i].unite((LL)e[j].first,(LL)e[j].second);
        }
        if(uft[i].count() != 1) ans++;
    }
    cout << ans << "\n";
}

Compiler output:
In file included from /usr/include/c++/14/algorithm:60,
                 from /usr/include/x86_64-linux-gnu/c++/14/bits/stdc++.h:51,
                 from a.cc:3:
/usr/include/c++/14/bits/stl_algobase.h: In instantiation of 'typename __gnu_cxx::__enable_if<(! std::__is_scalar<_Tp>::__value), void>::__type std::__fill_a1(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardIterator = UnionFindTree<51>*; _Tp = UnionFindTree<51>; typename __gnu_cxx::__enable_if<(! __is_scalar<_Tp>::__value), void>::__type = void]':
/usr/include/c++/14/bits/stl_algobase.h:998:21:   required from 'void std::__fill_a(_FIte, _FIte, const _Tp&) [with _FIte = UnionFindTree<51>*; _Tp = UnionFindTree<51>]'
  998 |     { std::__fill_a1(__first, __last, __value); }
      |       ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_algobase.h:1029:20:   required from 'void std::fill(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardIterator = UnionFindTree<51>*; _Tp = UnionFindTree<51>]'
 1029 |       std::__fill_a(__first, __last, __value);
      |       ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/vector.tcc:727:14:   required from 'void std::vector<_Tp, _Alloc>::_M_fill_insert(iterator, size_type, const value_type&) [with _Tp = UnionFindTree<51>; _Alloc = std::allocator<UnionFindTree<51> >; iterator = std::vector<UnionFindTree<51>, std::allocator<UnionFindTree<51> > >::iterator; size_type = long unsigned int; value_type = UnionFindTree<51>]'
  727 |                   std::fill(__position.base(), __position.base() + __n,
      |                   ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  728 |                             __x_copy);
      |                             ~~~~~~~~~
/usr/include/c++/14/bits/stl_vector.h:1037:4:   required from 'void std::vector<_Tp, _Alloc>::resize(size_type, const value_type&) [with _Tp = UnionFindTree<51>; _Alloc = std::allocator<UnionFindTree<51> >; size_type = long unsigned int; value_type = UnionFindTree<51>]'
 1037 |           _M_fill_insert(end(), __new_size - size(), __x);
      |           ^~~~~~~~~~~~~~
a.cc:94:15:   required from here
   94 |     uft.resize(m, UnionFindTree<51>{m});
      |     ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_algobase.h:940:18: error: use of deleted function 'UnionFindTree<51>& UnionFindTree<51>::operator=(const UnionFindTree<51>&)'
  940 |         *__first = __value;
      |         ~~~~~~~~~^~~~~~~~~
a.cc:36:7: note: 'UnionFindTree<51>& UnionFindTree<51>::operator=(const UnionFindTree<51>&)' is implicitly deleted because the default definition would be ill-formed:
   36 | class UnionFindTree {
      |       ^~~~~~~~~~~~~
a.cc:36:7: error: non-static const member 'const LL UnionFindTree<51>::len', cannot use default assignment operator
/usr/include/c++/14/bits/stl_algobase.h:940:18: note: use '-fdiagnostics-all-candidates' to display considered candidates
  940 |         *__first = __value;
      |         ~~~~~~~~~^~~~~~~~~
/usr/include/c++/14/bits/stl_algobase.h: In instantiation of 'static void std::__copy_move<true, false, std::random_access_iterator_tag>::__assign_one(_Tp*, _Up*) [with _Tp = UnionFindTree<51>; _Up = UnionFindTree<51>]':
/usr/include/c++/14/bits/stl_algobase.h:769:20:   required from 'static _Up* std::__copy_move_backward<_IsMove, true, std::random_access_iterator_tag>::__copy_move_b(_Tp*, _Tp*, _Up*) [with _Tp = UnionFindTree<51>; _Up = UnionFindTree<51>; bool _IsMove = true]'
  768 |             std::__copy_move<_IsMove, false, random_access_iterator_tag>::
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  769 |               __assign_one(__result - 1, __first);
      |               ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_algobase.h:787:37:   required from '_BI2 std::__copy_move_backward_a2(_BI1, _BI1, _BI2) [with bool _IsMove = true; _BI1 = UnionFindTree<51>*; _BI2 = UnionFindTree<51>*]'
  785 |       return std::__copy_move_backward<_IsMove,
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                  
  786 |                                        __memcpyable<_BI2, _BI1>::__value,
      |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  787 |                                        _Category>::__copy_move_b(__first,
      |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
  788 |                                                                  __last,
      |                                                                  ~~~~~~~
  789 |                                                                  __result);
      |                                                                  ~~~~~~~~~
/usr/include/c++/14/bits/stl_algobase.h:796:51:   required from '_BI2 std::__copy_move_backward_a1(_BI1, _BI1, _BI2) [with bool _IsMove = true; _BI1 = UnionFindTree<51>*; _BI2 = UnionFindTree<51>*]'
  796 |     { return std::__copy_move_backward_a2<_IsMove>(__first, __last, __result); }
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_algobase.h:827:5:   required from '_OI std::__copy_move_backward_a(_II, _II, _OI) [with bool _IsMove = true; _II = UnionFindTree<51>*; _OI = UnionFindTree<51>*]'
  826 |                 std::__copy_move_backward_a1<_IsMove>
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  827 |                   (std::__niter_base(__first), std::__niter_base(__last),
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  828 |                    std::__niter_base(__result)));
      |                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_algobase.h:922:47:   required from '_BI2 std::move_backward(_BI1, _BI1, _BI2) [with _BI1 = UnionFindTree<51>*; _BI2 = UnionFindTree<51>*]'
  922 |       return std::__copy_move_backward_a<true>(std::__miter_base(__first),
      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
  923 |                                                std::__miter_base(__last),
      |                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~
  924 |                                                __result);
      |                                                ~~~~~~~~~
/usr/include/c++/14/bits/vector.tcc:725:5:   required from 'void std::vector<_Tp, _Alloc>::_M_fill_insert(iterator, size_type, const value_type&) [with _Tp = UnionFindTree<51>; _Alloc = std::allocator<UnionFindTree<51> >; iterator = std::vector<UnionFindTree<51>, std::allocator<UnionFindTree<51> > >::iterator; size_type = long unsigned int; value_type = UnionFindTree<51>]'
  725 |                   _GLIBCXX_MOVE_BACKWARD3(__position.base(),
      |                   ^~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_vector.h:1037:4:   required from 'void std::vector<_Tp, _Alloc>::resize(size_type, const value_type&) [with _Tp = UnionFindTree<51>; _Alloc = std::allocator<UnionFindTree<51> >; size_type = long unsigned int; value_type = UnionFindTree<51>]'
 1037 |           _M_fill_insert(end(), __new_size - size(), __x);
      |           ^~~~~~~~~~~~~~
a.cc:94:15:   required from here
   94 |     uft.resize(m, UnionFindTree<51>{m});
      |     ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_algobase.h:438:17: error: use of deleted function 'UnionFindTree<51>& UnionFindTree<51>::operator=(UnionFindTree<51>&&)'
  438 |         { *__to = std::move(*__from); }
      |           ~~~~~~^~~~~~~~~~~~~~~~~~~~
a.cc:36:7: note: 'UnionFindTree<51>& UnionFindTree<51>::operator=(UnionFindTree<51>&&)' is implicitly deleted because the default definition would be ill-formed:
   36 | class UnionFindTree {
      |       ^~~~~~~~~~~~~
a.cc:36:7: error: non-static const member 'const LL UnionFindTree<51>::len', cannot use default assignment operator
/usr/include/c++/14/bits/stl_algobase.h:438:17: note: use '-fdiagnostics-all-candidates' to display considered candidates
  438 |         { *__to = std::move(*__from); }
      |           ~~~~~~^~~~~~~~~~~~~~~~~~~~