Problem:
Party
The students in a class in Akabe high-school define the relation “acquaintance” as:
If A and B are friends, then A is acquainted with B.
If A and B are friends and B is acquainted with C, then A is acquainted with C.
They define the relation “companion” as:
Suppose A is acquainted with B, and two classmates who have been friend distance. If A is still acquainted with B, then A and B are companions.
A boy PCK joined the class recently and wishes to hold a party inviting his class fellows. He wishes to invite as many boys and girls as possible to the party and has written up an invitation list. In arranging the list, he placed the following conditions based on the acquaintanceship within the class before he joined.
When T is in the list:
U is listed if he/she is a companion of T.
If U is not a companion of T, U is not listed if he/she and T are friends, or he/she and some of T’s companions are friends.
PCK made the invitation list so that the maximum number of his classmates is included.
Given the number of classmates
N
and the friendships among them, write a program to estimate the number of boys and girls in the list. All the classmates are identified by an index that ranges from 0 to
N
-1.
Input
The input is given in the following format.
N
M
s_1
t_1
s_2
t_2
:
s_M
t_M
The first line provides the number of classmates
N
(2 ≤
N
≤ 10
5
) and the number of friendships
M
(1 ≤
M
≤ 2×10
5
). Each of the
M
subsequent lines provides two of the classmates
s_i, t_i
(0 ≤
s_i,t_i
≤
N
-1) indicating they are friends. No duplicate relationship appears among these lines.
Output
Output the maximum number of classmates PCK invited to the party.
Sample Input 1
7 8
0 1
1 2
1 3
2 3
0 4
4 5
4 6
5 6
Sample Output 1
6
Sample Input 2
3 2
0 1
1 2
Sample Output 2
2

Submitted solutions:

code_snippet: // AOJ #377
// Party 2025.2.9

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

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {  // 整数の入力
	int n = 0, c = gc();
	if (c == '-') {	c = gc();
		do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
		return -n;
	}
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(ll n) { // 整数の表示（出力）
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

struct Edge {
    int to;
    int id;
};
 
int timer = 0;
 
void dfs_bridges(int v, int parentEdge, const vector<vector<Edge>> &g, 
                 vector<int> &tin, vector<int> &low, vector<bool> &visited, 
                 vector<bool> &isBridge) {
    visited[v] = true;
    tin[v] = low[v] = timer++;
    for(auto &edge : g[v]){
        int to = edge.to, id = edge.id;
        if(id == parentEdge) continue;
        if(!visited[to]){
            dfs_bridges(to, id, g, tin, low, visited, isBridge);
            low[v] = min(low[v], low[to]);
            if(low[to] > tin[v]){
                isBridge[id] = true;
            }
        } else {
            low[v] = min(low[v], tin[to]);
        }
    }
}
 
int main() {
    int N = Cin(), M = Cin();
    vector<vector<Edge>> g(N);
    vector<pair<int,int>> edges;
    edges.reserve(M);
 
    for (int i = 0; i < M; i++){
        int u = Cin(), v = Cin();
        edges.push_back({u,v});
        g[u].push_back({v, i});
        g[v].push_back({u, i});
    }
 
    vector<int> tin(N, -1), low(N, -1);
    vector<bool> visited(N, false);
    vector<bool> isBridge(M, false);
    timer = 0;
    for (int i = 0; i < N; i++){
        if(!visited[i])
            dfs_bridges(i, -1, g, tin, low, visited, isBridge);
    }
 
    vector<int> comp(N, -1);
    int compIndex = 0;
    for (int i = 0; i < N; i++){
        if(comp[i] == -1){
            queue<int> q;
            q.push(i);
            comp[i] = compIndex;
            while(!q.empty()){
                int cur = q.front();
                q.pop();
                for(auto &edge : g[cur]){
                    if(isBridge[edge.id]) continue;
                    int nxt = edge.to;
                    if(comp[nxt] == -1){
                        comp[nxt] = compIndex;
                        q.push(nxt);
                    }
                }
            }
            compIndex++;
        }
    }
 
    vector<int> compWeight(compIndex, 0);
    for (int i = 0; i < N; i++){
        compWeight[ comp[i] ]++;
    }
 
    vector<vector<int>> tree(compIndex);
    for (int i = 0; i < M; i++){
        if(isBridge[i]){
            int u = edges[i].first, v = edges[i].second;
            int cu = comp[u], cv = comp[v];
            tree[cu].push_back(cv);
            tree[cv].push_back(cu);
        }
    }
 
    vector<bool> visTree(compIndex, false);
    vector<array<ll,2>> dp(compIndex, {0,0});
 
    function<void(int,int)> dfs_tree = [&](int u, int parent){
        visTree[u] = true;
        dp[u][1] = compWeight[u];
        dp[u][0] = 0;
        for (int v : tree[u]){
            if(v == parent) continue;
            if(!visTree[v]) dfs_tree(v, u);
            dp[u][1] += dp[v][0];
            dp[u][0] += max(dp[v][0], dp[v][1]);
        }
    };
 
    ll ans = 0;
    for (int i = 0; i < compIndex; i++){
        if(!visTree[i]){
            dfs_tree(i, -1);
            ans += max(dp[i][0], dp[i][1]);
        }
    }
    Cout(ans);
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 18324
final_rank: 1

code_snippet: /* -*- coding: utf-8 -*-
 *
 * 0377.cc: Party
 */

#include<cstdio>
#include<vector>
#include<stack>
#include<algorithm>
#include<utility>
 
using namespace std;

/* constant */

const int MAX_N = 100000;
const int MAX_M = 200000;

/* typedef */

typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<bool> vb;
typedef vector<vi> vvi;
typedef vector<pii> vpii;
typedef stack<int> si;

/* global variables */

pii es[MAX_M];
vi nbrs[MAX_N], gnbrs[MAX_N];
int gids[MAX_N], ps[MAX_N], cis[MAX_N], mss[MAX_N][2];
bool used[MAX_N];

/* subroutines */

void bcc_visit(const vi *nbrs, int v, int u, vpii& brdg, vvi& tecomp,
	       si& roots, si& S, vb& inS, vi& num, int& time) {
  num[v] = ++time;
  S.push(v); inS[v] = true;
  roots.push(v);

  const vi& nbrv = nbrs[v];
  for (vi::const_iterator vit = nbrv.begin(); vit != nbrv.end(); vit++) {
    const int& w = *vit;
    if (num[w] == 0)
      bcc_visit(nbrs, w, v, brdg, tecomp, roots, S, inS, num, time);
    else if (u != w && inS[w])
      while (num[roots.top()] > num[w]) roots.pop();
  }

  if (v == roots.top()) {
    brdg.push_back(pii(u, v));
    tecomp.push_back(vi());
    for (;;) {
      int w = S.top(); S.pop(); inS[w] = false;
      tecomp.back().push_back(w);
      if (v == w) break;
    }
    roots.pop();
  }
}

void calc_bcc(const int n, const vi *nbrs, vpii& brdg, vvi& tecomp) {
  vi num(n);
  vb inS(n);
  si roots, S;
  int time = 0;

  for (int u = 0; u < n; u++)
    if (num[u] == 0) {
      bcc_visit(nbrs, u, n, brdg, tecomp, roots, S, inS, num, time);
      brdg.pop_back();
    }
}

/* main */

int main() {
  int n, m;
  scanf("%d%d", &n, &m);

  for (int i = 0; i < m; i++) {
    int u, v;
    scanf("%d%d", &u, &v);
    es[i] = pii(u, v);
    nbrs[u].push_back(v);
    nbrs[v].push_back(u);
  }

  vpii brdg;
  vvi tcmp;
  calc_bcc(n, nbrs, brdg, tcmp);

  int gn = tcmp.size();
  for (int i = 0; i < gn; i++)
    for (auto u: tcmp[i]) gids[u] = i;

  //printf("gn=%d\n", gn);
  //for (int i = 0; i < gn; i++) printf("%d ", (int)tcmp[i].size());
  //putchar('\n');

  for (int i = 0; i < m; i++) {
    int gu = gids[es[i].first], gv = gids[es[i].second];
    if (gu != gv) {
      gnbrs[gu].push_back(gv);
      gnbrs[gv].push_back(gu);
      //printf("%d-%d\n", gu, gv);
    }
  }

  int sum = 0;
  for (int st = 0; st < gn; st++)
    if (! used[st]) {
      ps[st] = -1, used[st] = true;
      
      for (int u = st; u >= 0;) {
	vi &gnbru = gnbrs[u];
	int up = ps[u];

	if (cis[u] < gnbru.size()) {
	  int v = gnbru[cis[u]++];
	  if (! used[v]) {
	    ps[v] = u, used[v] = true;
	    u = v;
	  }
	}
	else {
	  mss[u][1] += tcmp[u].size();

	  if (up >= 0) {
	    mss[up][0] += max(mss[u][0], mss[u][1]);
	    mss[up][1] += mss[u][0];
	  }
	  
	  u = up;
	}
      }

      sum += max(mss[st][0], mss[st][1]);
    }

  printf("%d\n", sum);
  return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 23284
final_rank: 5

code_snippet: //#pragma GCC target ("avx2")
//#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#define _USE_MATH_DEFINES
#include<iostream>
#include<string>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<list>
#include<iomanip>
#include<vector>
#include<random>
#include<functional>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<unordered_map>
#include<climits>
#include<fstream>
#include<complex>
#include<time.h>
#include<cassert>
#include<functional>
#include<numeric>
#include<tuple>
using namespace std;
using ll = long long;
using ld = long double;
using H = pair<ll, ll>;
using P = pair<ll, H>;
using vi = vector<ll>;
#define all(a) (a).begin(),(a).end()
#define fs first
#define sc second
#define xx first
#define yy second.first
#define zz second.second
#define Q(i,j,k) mkp((i),mkp((j),(k)))
#define rng(i,s,n) for(ll i = (s) ; i < (n) ; i++)
#define rep(i,n) rng(i, 0, (n))
#define mkp make_pair
#define vec vector
#define pb emplace_back
#define siz(a) int((a).size())
#define crdcomp(b) sort(all((b)));(b).erase(unique(all((b))),(b).end())
#define getidx(b,i) (lower_bound(all((b)),(i))-(b).begin())
#define ssp(i,n) (i==(ll)(n)-1?"\n":" ")
#define ctoi(c) (int)((c)-'0')
#define itoc(c) (char)((c)+'0')
#define cyes printf("Yes\n")
#define cno printf("No\n")
#define cdf(n) for(int quetimes_=(n);quetimes_>0;quetimes_--)
#define gcj printf("Case #%lld: ",quetimes_+1)
#define readv(a,n) (a).resize((n),0);rep(i,(n)) (a)[i]=read()
#define found(a,x) (a.find(x)!=a.end())
constexpr ll mod = (ll)1e9 + 7;
constexpr ll Mod = 998244353;
constexpr ld EPS = 1e-10;
constexpr ll inf = (ll)3 * 1e18;
constexpr int Inf = 1e9;
constexpr int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };
template<class T>bool chmax(T& a, const T& b) { if (a < b) { a = b; return 1; } return 0; }
template<class T>bool chmin(T& a, const T& b) { if (b < a) { a = b; return 1; } return 0; }
ll read() { ll u, k = scanf("%lld", &u); return u; }
string reads() { string s; cin >> s; return s; }
H readh(short g = 0) { H u; int k = scanf("%lld %lld", &u.fs, &u.sc); if (g == 1) u.fs--, u.sc--; if (g == 2) u.fs--; return u; }
bool ina(H t, int h, int w) { return 0 <= t.fs && t.fs < h && 0 <= t.sc && t.sc < w; }
bool ina(int t, int l, int r) { return l <= t && t < r; }
ll gcd(ll i, ll j) { return j ? gcd(j, i % j) : i; }
ll ppc(ll x) {
    int sum = 0; for (int i = 0; i < 60; i++)if ((1ll << i) & x) sum++;
    return sum;
}
template<typename T>
void fin(T x) { cout << x << endl; exit(0); }

template<typename T>
class csum {
    vec<T> v;
public:
    csum(vec<T>& a) :v(a) { build(); }
    csum() {}
    csum(int sz) { init(sz); }
    void init(int sz) { v = vector<T>(sz + 1, 0); }
    void init(vec<T>& a) { v = a; build(); }
    void build() {
        for (int i = 1; i < v.size(); i++) v[i] += v[i - 1];
    }
    void add(int l, int r, T x) {
        v[l] += x;
        v[r] -= x;
    }//[l,r)
    void add(int t, T x) {
        v[t] += x;
    }//[l,r)
    //[l,r]
    T a(int l, int r) {
        if (r < l) return 0;
        return v[r] - (l == 0 ? 0 : v[l - 1]);
    }
    //[l,r)
    T b(int l, int r) {
        return a(l, r - 1);
    }
    T a(pair<int, int>t) {
        return a(t.first, t.second);
    }
    T b(pair<int, int>t) {
        return b(t.first, t.second);
    }
    T operator[](int x)const {
        return v[x];
    }
};
class via {
    using H = pair<ll, ll>;
    bool comp;
public:
    vector<H>a;
    via() :comp(true) {}
    via(vector<H>dat) :a(dat), comp(false) { build(); }
    void push(int l, int r) { a.push_back(H{ l,r }); comp = false; }
    void push(H a) { push(a.first, a.second); }
    void build() {
        if (comp) return;
        comp = true;
        sort(a.begin(), a.end());
        int fst = -1; ll lst = -1;
        vector<H>b;
        for (int i = 0; i < a.size(); i++) {
            if (fst < 0) fst = i, lst = a[i].second;
            if (lst < a[i].first) {
                b.push_back(H{ a[fst].first,lst });
                fst = i, lst = a[i].second;
            }
            else if (lst < a[i].second) lst = a[i].second;
        }
        if (~fst) b.push_back(H{ a[fst].first, lst });
        a = b;
    }
    ll size() { return ll(a.size()); }
    ll sum() {
        build();
        ll sum = 0;
        for (auto g : a) sum += g.second - g.first;
        return sum;
    }
    via inter(via& v) {
        build(); v.build();
        via ret;
        for (auto g : a) ret.push(g);
        for (auto g : v.a) ret.push(g);
        ret.build(); return ret;
    }
    via comb(via& v) {
        build(); v.build();
        int s = 0, t = 0;
        via ret;
        while (s < a.size() && t < v.size()) {
            if (v[t].second <= a[s].first)  t++;
            else if (a[s].second <= v[t].first) s++;
            else {
                ret.push(max(a[s].first, v[t].first), min(a[s].second, v[t].second));
                if (a[s].second <= v[t].second) s++;
                else t++;
            }
        }
        return ret;
    }
    H& operator[](int t) { return a[t]; }
};
template<ll mod>
class modint {
public:ll v;
      modint(ll v = 0) { s(v % mod + mod); }
      constexpr static int fn_ = (ll)2e6 + 5;
      static vector<modint>fact, comp;
      modint pow(ll x) const {
          modint b(v), c(1);
          while (x) {
              if (x & 1) c *= b;
              b *= b;
              x >>= 1;
          }
          return c;
      }
      inline modint& s(int vv) {
          v = vv < mod ? vv : vv - mod;
          return *this;
      }
      inline modint inv()const { return pow(mod - 2); }
      inline modint operator-()const { return modint() - *this; }
      inline modint& operator+=(const modint b) { return s(v + b.v); }
      inline modint& operator-=(const modint b) { return s(v + mod - b.v); }
      inline modint& operator*=(const modint b) { v = v * b.v % mod; return *this; }
      inline modint& operator/=(const modint b) { v = v * b.inv().v % mod; return *this; }
      inline modint operator+(const modint& b) const { return modint(v) += b; }
      inline modint operator-(const modint& b) const { return modint(v) -= b; }
      inline modint operator*(const modint& b) const { return modint(v) *= b; }
      inline modint operator/(const modint& b) const { return modint(v) /= b; }
      friend ostream& operator<<(ostream& os, const modint& m) {
          return os << m.v;
      }
      friend istream& operator>>(istream& is, modint& m) {
          int x; is >> x; m = modint(x);
          return is;
      }
      bool operator<(const modint& r)const { return v < r.v; }
      bool operator>(const modint& r)const { return v > r.v; }
      bool operator<=(const modint& r)const { return v <= r.v; }
      bool operator>=(const modint& r)const { return v >= r.v; }
      bool operator==(const modint& r)const { return v == r.v; }
      bool operator!=(const modint& r)const { return v != r.v; }
      explicit operator bool()const { return v; }
      explicit operator int()const { return v; }
      modint comb(modint k) {
          if (k > *this) return modint();
          if (fact.empty()) combinit();
          if (v >= fn_) {
              if (k > *this - k) k = *this - k;
              modint tmp(1);
              for (int i = v; i >= v - k.v + 1; i--) tmp *= modint(i);
              return tmp * comp[k.v];
          }
          return fact[v] * comp[k.v] * comp[v - k.v];
      }//nCk
      modint perm(modint k) {
          if (k > *this) return modint();
          if (fact.empty()) combinit();
          if (v >= fn_) {
              modint tmp(1);
              for (int i = v; i >= v - k.v + 1; i--) tmp *= modint(i);
              return tmp;
          }
          return fact[v] * comp[v - k.v];
      }//nPk
      static void combinit() {
          fact.assign(fn_, modint());
          fact[0] = 1;
          for (int i = 1; i < fn_; i++) fact[i] = fact[i - 1] * modint(i);
          comp.assign(fn_, modint());
          comp[fn_ - 1] = fact[fn_ - 1].inv();
          for (int i = fn_ - 2; i >= 0; i--) comp[i] = comp[i + 1] * modint(i + 1);
      }
};
using mint = modint<ll(1e9 + 7)>; template<>vec<mint> mint::fact = vec<mint>(); template<>vec<mint> mint::comp = vec<mint>();
//--------------------------------------------------------------
//--------------------------------------------------------------
class unionfind {
    int size = 0, grps = 0;
    vector<int>pa;
public:
    unionfind() {}
    unionfind(int n) {
        init(n);
    }
    void init(int n) {
        size = n, grps = n;
        pa.assign(n, -1);
    }
    int root(int x) {
        if (pa[x] < 0) return x;
        return pa[x] = root(pa[x]);
    }
    bool unite(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) return false;
        grps--;
        if (pa[x] > pa[y]) swap(x, y);
        pa[x] += pa[y];
        pa[y] = x;
        return true;
    }
    bool same(int x, int y) {
        return root(x) == root(y);
    }
    bool isroot(int x) {
        return x == root(x);
    }
    int sz(int x) {
        return -pa[root(x)];
    }
    int groups() {
        return grps;
    }
    H operator[](int x) {
        x = root(x);
        return H{ x,-pa[x] };
    }
};


int n, m;
vec<int>e[200000], f[200000];
vec<H>edg;
unionfind uf;
int dpt[200000];
int solve(int x, int p, int d) {
    dpt[x] = d;
    int mn = n + 1;
    for (auto g : e[x]) {
        if (g == p) continue;
        if (~dpt[g]) chmin(mn, dpt[g]);
        else chmin(mn, solve(g, x, d + 1));
    }
    if (mn < d) {
        uf.unite(x, p);
    }
    return mn;
}

int sz[200000];
int dp[200000][2];

int dfs(int x, int p, int can, int d) {
    if (d > 2e5) {
        return 0;
    }
    if (~dp[x][can]) return dp[x][can];
    int zero = 0, one = 0;
    for (auto g : f[x]) {
        if (g == p) continue;
        zero += dfs(g, x, 1, d + 1);
        one += dfs(g, x, 0, d + 1);
    }
    dp[x][1] = max(zero, one + sz[x]);
    dp[x][0] = zero;
    return dp[x][can];
}


signed main() {
    mt19937 rnd;
    //while (1) {
        cin >> n >> m;
        //n = rnd() % 100000, m = rnd() % 200000;
        rep(i, n) {
            e[i].clear(), f[i].clear(), sz[i] = 0, dp[i][0] = dp[i][1] = -1;
        }
        edg.clear();

        unionfind uf2(n);
        rep(i, m) {
            int u, v; cin >> u >> v;
            //u = rnd() % n, v = rnd() % n; while (u == v) v = rnd() % n;
            e[u].pb(v); e[v].pb(u);
            edg.pb(u, v);
            uf2.unite(u, v);
        }
        uf = unionfind(n);

        rep(i, n) dpt[i] = -1;
        rep(i,n) if(uf2.root(i)==i) solve(i, -1, 0);
        vec<int>pos;
        rep(i, n) {
            if (uf.root(i) == i) {
                pos.pb(i);
                sz[i] = uf.sz(i);
            }
        }
        rep(i, m) {
            if (!uf.same(edg[i].fs, edg[i].sc)) {
                f[uf.root(edg[i].fs)].pb(uf.root(edg[i].sc));
                f[uf.root(edg[i].sc)].pb(uf.root(edg[i].fs));
            }
        }

        vec<bool>eval(n, 0);
        int ans = 0;
        rep(i, n) {
            if (uf.root(i) == i && !eval[uf2.root(i)]) {
                ans += dfs(i, -1, 1, 0);
                eval[uf2.root(i)] = 1;
            }
        }
        cout << ans << endl;
    
}
accuracy: 1
time_ms: 50
memory_kb: 23812
final_rank: 9

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <set>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>
#include <sstream>
#include <bitset>
#include <complex>
#include <chrono>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

int main() {
	int n, m; std::cin >> n >> m;
	std::vector<std::vector<int>> nodes(n);
	for (auto i = 0; i < m; ++i) {
		int s, t; std::cin >> s >> t;
		nodes[s].push_back(t);
		nodes[t].push_back(s);
	}
	std::vector<int> in_time(n, -1), out_time(n, -1), parent(n, -1);
	int time{ 0 };
	std::stack<int> stack;
	for (auto i = 0; i < n; ++i) {
		if (in_time[i] >= 0) continue;
		stack.push(i);
		while (!stack.empty()) {
			const auto top = stack.top(); stack.pop();
			if (top >= 0) {
				if (in_time[top] >= 0) continue;
				in_time[top] = time++;
				stack.push(-1 - top);
				for (const auto next : nodes[top]) {
					if (in_time[next] >= 0) continue;
					stack.push(next);
					parent[next] = top;
				}
			}
			else {
				out_time[-1 - top] = time++;
			}
		}
	}
	std::vector<int> root(n); std::iota(root.begin(), root.end(), 0);
	for (auto i = 0; i < n; ++i) {
		for (const auto j : nodes[i]) {
			if (j == parent[i]) continue;
			if (in_time[i] < in_time[j]) continue;
			auto r = j;
			while (out_time[r] < out_time[i] || root[r] != r) {
				if (root[r] != r) {
					r = root[r];
				}
				else {
					r = parent[r];
				}
			}
			auto p = j;
			while (p != r) {
				if (root[p] != p) {
					const auto next = root[p];
					root[p] = r;
					p = next;
				}
				else {
					root[p] = r;
					p = parent[p];
				}
			}
			p = i;
			while (p != r) {
				if (root[p] != p) {
					const auto next = root[p];
					root[p] = r;
					p = next;
				}
				else {
					root[p] = r;
					p = parent[p];
				}
			}
		}
	}
	for (auto i = 0; i < n; ++i) {
		if (root[i] != i) {
			auto r = i;
			while (root[r] != r) {
				r = root[r];
			}
			auto p = i;
			while (root[p] != r) {
				const auto next = root[p];
				root[p] = r;
				p = next;
			}
		}
	}
	std::vector<std::vector<int>> group(n);
	for (auto i = 0; i < n; ++i) {
		group[root[i]].push_back(i);
	}
	std::vector<int> invite(n, 0), not_invite(n, 0), history, roots;
	std::vector<bool> visit(n, false);
	for (auto i = 0; i < n; ++i) {
		if (visit[root[i]]) continue;
		roots.push_back(i);
		visit[root[i]] = true;
		stack.push(root[i]);
		while (!stack.empty()) {
			const auto top = stack.top(); stack.pop();
			history.push_back(top);
			for (const auto s : group[top]) {
				for (const auto next : nodes[s]) {
					if (visit[root[next]]) continue;
					visit[root[next]] = true;
					stack.push(root[next]);
				}
			}
		}
	}
	std::reverse(history.begin(), history.end());
	for (const auto i : history) {
		int invite_count = group[i].size(), not_invite_count = 0;
		for (const auto s : group[i]) {
			for (const auto next : nodes[s]) {
				if (i == root[next]) continue;
				invite_count += not_invite[next];
				not_invite_count += std::max(not_invite[next], invite[next]);
			}
		}
		invite[i] = invite_count;
		not_invite[i] = not_invite_count;
	}
	int result{ 0 };
	for (const auto r : roots) {
		result += std::max(invite[r], not_invite[r]);
	}
	std::cout << result << '\n';
}
accuracy: 1
time_ms: 50
memory_kb: 16960
final_rank: 2

code_snippet: #line 1 "a.cpp"
#include<iostream>
#include<algorithm>
using namespace std;
#line 1 "/home/kotatsugame/library/graph/TECC.cpp"
//Two Edge Connected Components require bridge
#line 1 "/home/kotatsugame/library/graph/bridge.cpp"
#include<vector>
#line 3 "/home/kotatsugame/library/graph/bridge.cpp"
struct bridge{
	int n;
	vector<int>ord,low;
	vector<bool>art;
	vector<vector<int> >G;
	bridge(int n_=0):n(n_),ord(n_,-1),low(n_),art(n_,false),G(n_){}
	void add_edge(int u,int v)
	{
		G[u].push_back(v);
		G[v].push_back(u);
	}
	bool operator[](int i)const{return art[i];}
	bool is_bridge(int a,int b)const
	{
		if(ord[a]>ord[b])swap(a,b);
		return ord[a]<low[b];
	}
	void dfs(int u,int p,int&k)
	{
		low[u]=ord[u]=k++;
		bool now=false;
		int pc=0;
		for(int v:G[u])
		{
			if(ord[v]==-1)
			{
				dfs(v,u,k);
				low[u]=min(low[u],low[v]);
				now=now||ord[u]<=low[v];
			}
			else if(v!=p||pc++)
			{
				low[u]=min(low[u],ord[v]);
			}
		}
		art[u]=now;
	}
	void build()
	{
		int k=0;
		for(int u=0;u<n;u++)if(ord[u]==-1)
		{
			int cnt=0;
			low[u]=ord[u]=k++;
			for(int v:G[u])if(ord[v]==-1)
			{
				dfs(v,u,k);
				cnt++;
			}
			if(cnt>=2)art[u]=true;
		}
	}
};
#line 3 "/home/kotatsugame/library/graph/TECC.cpp"
struct TECC:bridge{
	vector<int>comp;
	TECC(int n_=0):bridge(n_),comp(n_,-1){}
	int operator[](int i)const{return comp[i];}
	void dfs(int u,int p,int&k)
	{
		comp[u]=p==-1||is_bridge(p,u)?k++:comp[p];
		for(int v:G[u])if(comp[v]==-1)dfs(v,u,k);
	}
	int build()
	{
		bridge::build();
		int k=0;
		for(int u=0;u<n;u++)if(comp[u]==-1)dfs(u,-1,k);
		return k;
	}
	int build(vector<vector<int> >&H)
	{
		int k=build();
		H.assign(k,vector<int>());
		for(int u=0;u<n;u++)
		{
			for(int v:G[u])if(comp[u]!=comp[v])
			{
				H[comp[u]].push_back(comp[v]);
			}
		}
		return k;
	}
};
#line 5 "a.cpp"
int N,M,K;
vector<vector<int> >G;
int cnt[1<<17];
bool vis[1<<17];
pair<int,int>dfs(int u)
{
	vis[u]=true;
	pair<int,int>ret;
	ret.first=cnt[u];
	ret.second=0;
	for(int v:G[u])if(!vis[v])
	{
		pair<int,int>q=dfs(v);
		ret.first+=q.second;
		ret.second+=q.first;
	}
	if(ret.first<ret.second)ret.first=ret.second;
	return ret;
}
main()
{
	cin>>N>>M;
	TECC P(N);
	for(int i=0;i<M;i++)
	{
		int u,v;cin>>u>>v;
		P.add_edge(u,v);
	}
	K=P.build(G);
	for(int i=0;i<N;i++)cnt[P[i]]++;
	int ans=0;
	for(int i=0;i<K;i++)if(!vis[i])
	{
		ans+=dfs(i).first;
	}
	cout<<ans<<endl;
}
accuracy: 1
time_ms: 70
memory_kb: 15656
final_rank: 3

code_snippet: #include<bits/stdc++.h>
#define all(vec) vec.begin(),vec.end()
#define eb emplace_back
using namespace std;
const char newl='\n';
template<class T>
using V=vector<T>;
using P=pair<int,int>;
using ll=long long;
const ll inf=1LL<<60;
void ok(){
    cout<<"OK"<<newl;
}
int n,m;
V<V<int>> G,g;
V<int> ord,low,vis,cnt;
int pos;
void dfs(int i,int p){
    vis[i]=1;
    ord[i]=pos;
    pos++;
    low[i]=ord[i];
    bool f=false;
    for(auto &e:G[i]){
        if(vis[e]){
            if(e!=p||f)low[i]=min(low[i],ord[e]);
            if(e==p)f=true;
            continue;
        }
        dfs(e,i);
        low[i]=min(low[i],low[e]);
    }
}
void bcc(int i,int c){
    vis[i]=1;
    cnt[c]++;
    for(auto &e:G[i]){
        if(vis[e])continue;
        if(ord[i]<low[e]){
            pos++;
            g[c].eb(pos);
            g[pos].eb(c);
            bcc(e,pos);
        }else{
            bcc(e,c);
        }
    }
}
V<V<int>> dp;
void calc(int i,int p){
    dp[i][0]=0;
    dp[i][1]=cnt[i];
    int s1=0;
    for(auto &e:g[i]){
        if(e==p)continue;
        calc(e,i);
        dp[i][1]+=dp[e][0];
        dp[i][0]+=max(dp[e][0],dp[e][1]);
    }
}
int main(){
    cin>>n>>m;
    G.resize(n);
    g.resize(n);
    ord.resize(n);
    low.resize(n);
    cnt.resize(n);
    vis.resize(n);
    for(int i=0;i<m;i++){
        int s,t;cin>>s>>t;
        G[s].eb(t);
        G[t].eb(s);
    }
    pos=0;
    for(int i=0;i<n;i++){
        if(!vis[i]){
            dfs(i,-1);
        }
    }
    pos=-1;
    vis.assign(n,0);
    for(int i=0;i<n;i++){
        if(!vis[i]){
            pos++;
            bcc(i,pos);
        }
    }
    pos++;
    dp.resize(pos,V<int>(2,-1));
    int res=0;
    for(int i=0;i<pos;i++){
        if(dp[i][0]==-1){
            calc(i,-1);
            res+=max(dp[i][0],dp[i][1]);
        }
    }
    cout<<res<<newl;
}
accuracy: 1
time_ms: 70
memory_kb: 21016
final_rank: 11

code_snippet: #include <set>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
int main() {
	cin.tie(0);
	ios_base::sync_with_stdio(false);
	int N, M;
	cin >> N >> M;
	vector<vector<int> > G(N);
	for (int i = 0; i < M; ++i) {
		int a, b;
		cin >> a >> b;
		G[a].push_back(b);
		G[b].push_back(a);
	}
	vector<bool> vis(N);
	vector<int> par(N, -1), depth(N), lowlink(N, 1 << 30);
	function<void(int)> build_tree = [&](int pos) {
		vis[pos] = true;
		for (int i : G[pos]) {
			if (vis[i]) continue;
			par[i] = pos;
			depth[i] = depth[pos] + 1;
			build_tree(i);
		}
	};
	function<void(int)> get_lowlink = [&](int pos) {
		for (int i : G[pos]) {
			if (par[i] != pos && par[pos] != i) {
				lowlink[pos] = min(lowlink[pos], depth[i]);
			}
		}
		for (int i : G[pos]) {
			if (par[i] == pos) {
				get_lowlink(i);
				lowlink[pos] = min(lowlink[pos], lowlink[i]);
			}
		}
	};
	for (int i = 0; i < N; ++i) {
		if (!vis[i]) {
			build_tree(i);
			get_lowlink(i);
		}
	}
	set<pair<int, int> > bridge;
	for (int i = 0; i < N; ++i) {
		if (par[i] != -1 && lowlink[i] >= depth[i]) {
			bridge.insert(make_pair(i, par[i]));
			bridge.insert(make_pair(par[i], i));
		}
	}
	vector<vector<int> > G2(N);
	for (int i = 0; i < N; ++i) {
		for (int j : G[i]) {
			if (bridge.find(make_pair(i, j)) == bridge.end()) {
				G2[i].push_back(j);
			}
		}
	}
	vector<int> comps(N, -1);
	function<void(int, int)> find_comps = [&](int pos, int col) {
		comps[pos] = col;
		for (int i : G2[pos]) {
			if (comps[i] == -1) {
				find_comps(i, col);
			}
		}
	};
	int scol = 0;
	for (int i = 0; i < N; ++i) {
		if (comps[i] == -1) {
			find_comps(i, scol);
			++scol;
		}
	}
	vector<int> scomp(scol);
	for (int i = 0; i < N; ++i) {
		++scomp[comps[i]];
	}
	vector<vector<int> > G3(scol);
	for (pair<int, int> i : bridge) {
		G3[comps[i.first]].push_back(comps[i.second]);
	}
	vector<bool> vis3(scol, false);
	function<pair<int, int>(int, int)> calc = [&](int pos, int pre) {
		vis3[pos] = true;
		int s1 = 0, s2 = 0;
		for (int i : G3[pos]) {
			if (i == pre) continue;
			pair<int, int> res = calc(i, pos);
			s1 += res.first;
			s2 += max(res.first, res.second);
		}
		return make_pair(s2, s1 + scomp[pos]);
	};
	int ans = 0;
	for (int i = 0; i < scol; ++i) {
		if (!vis3[i]) {
			pair<int, int> res = calc(i, -1);
			ans += max(res.first, res.second);
		}
	}
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 27540
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
namespace lowlink{
  vector<vector<pair<int, int>>> roads_l;
  vector<int> label, lowlink;
  vector<bool> is_bridge;
  int dfs(int now, int back){
    lowlink[now] = label[now];
    int label_num = label[now];
    for (auto to : roads_l[now]){
      if (to.second == back){
        continue;
      }
      if (label[to.first] == -1){
        label[to.first] = label_num + 1;
        label_num = dfs(to.first, to.second);
        if (label[now] < lowlink[to.first]){
          is_bridge[to.second] = true;
        }
      }
      lowlink[now] = min(lowlink[now], lowlink[to.first]);
    }
    return label_num;
  }
  vector<bool> get_bridge(int N, vector<pair<int, int>> edges){
    roads_l.resize(N);
    int cnt = 0;
    for (auto i : edges){
      roads_l[i.first].push_back({i.second, cnt});
      roads_l[i.second].push_back({i.first, cnt});
      cnt++;
    }
    label = vector<int>(N, -1);
    lowlink = vector<int>(N, -1);
    is_bridge = vector<bool>(edges.size(), false);
    for (int i = 0; i < N; i++){
      if (label[i] == -1){
        label[i] = 0;
        dfs(i, -1);
      }
    }
    return is_bridge;
  }
}
void dfs(vector<int> &dp1, vector<int> &dp2, vector<vector<int>> &c, vector<int> &a, int v){
  dp1[v] = 0;
  dp2[v] = a[v];
  for (int w : c[v]){
    dfs(dp1, dp2, c, a, w);
    dp1[v] += max(dp1[w], dp2[w]);
    dp2[v] += dp1[w];
  }
}
int main(){
  int N, M;
  cin >> N >> M;
  vector<int> s(M), t(M);
  for (int i = 0; i < M; i++){
    cin >> s[i] >> t[i];
  }
  vector<pair<int, int>> edges(M);
  for (int i = 0; i < M; i++){
    edges[i] = make_pair(s[i], t[i]);
  }
  vector<bool> b = lowlink::get_bridge(N, edges);
  vector<vector<int>> E(N);
  for (int i = 0; i < M; i++){
    if (b[i] == 0){
      E[s[i]].push_back(t[i]);
      E[t[i]].push_back(s[i]);
    }
  }
  vector<int> con(N, -1);
  int cnt = 0;
  for (int i = 0; i < N; i++){
    if (con[i] == -1){
      con[i] = cnt;
      queue<int> Q;
      Q.push(i);
      while (!Q.empty()){
        int v = Q.front();
        Q.pop();
        for (int w : E[v]){
          if (con[w] == -1){
            con[w] = cnt;
            Q.push(w);
          }
        }
      }
      cnt++;
    }
  }
  vector<int> a(cnt, 0);
  for (int i = 0; i < N; i++){
    a[con[i]]++;
  }
  vector<vector<int>> E2(cnt + 1);
  for (int i = 0; i < M; i++){
    if (con[s[i]] != con[t[i]]){
      E2[con[s[i]]].push_back(con[t[i]]);
      E2[con[t[i]]].push_back(con[s[i]]);
    }
  }
  a.push_back(0);
  vector<bool> used(cnt, false);
  for (int i = 0; i < cnt; i++){
    if (!used[i]){
      E2[i].push_back(cnt);
      E2[cnt].push_back(i);
      used[i] = true;
      queue<int> Q;
      Q.push(i);
      while (!Q.empty()){
        int v = Q.front();
        Q.pop();
        for (int w : E2[v]){
          if (!used[w]){
            used[w] = true;
            Q.push(w);
          }
        }
      }
    }
  }
  cnt++;
  vector<int> p(cnt, -1);
  vector<vector<int>> c(cnt);
  queue<int> Q;
  Q.push(cnt - 1);
  while (!Q.empty()){
    int v = Q.front();
    Q.pop();
    for (int w : E2[v]){
      if (w != p[v]){
        p[w] = v;
        c[v].push_back(w);
        Q.push(w);
      }
    }
  }
  vector<int> dp1(cnt, 0);
  vector<int> dp2(cnt, 0);
  dfs(dp1, dp2, c, a, cnt - 1);
  cout << max(dp1[cnt - 1], dp2[cnt - 1]) << endl;
}
accuracy: 1
time_ms: 90
memory_kb: 25348
final_rank: 13

code_snippet: #include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

static const int MOD = 1000000007;
using ll = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max()/32*15+208;

class TwoEdgeConnectedComponents {
    void dfs(int i, int &pos){
        ord[i] = low[i] = pos++;
        int mul = 0;
        for (auto &&j : G[i]) {
            if(j == par[i] && !mul){
                mul = 1;
                continue;
            }
            if(~ord[j]){
                low[i] = min(low[i], ord[j]);
                continue;
            }
            par[j] = i;
            dfs(j, pos);
            size[i] += size[j];
            low[i] = min(low[i], low[j]);
        }
    }

    void dfs2(int i){
        out[bridge[i]].emplace_back(i);
        for (auto &&j : G[i]) {
            if(~bridge[j] || is_bridge(i, j)) continue;
            bridge[j] = bridge[i];
            dfs2(j);
        }
    }
public:
    vector<int> ord, low, par, bridge, size;
    vector<vector<int>> G, out;
    explicit TwoEdgeConnectedComponents(int n): ord(n, -1), low(n), par(n, -1), bridge(n, -1), size(n, 1), G(n){}

    inline bool is_bridge(int i, int j){
        if(ord[i] > ord[j]) swap(i, j);
        return ord[i] < low[j];
    }

    void add_edge(int u, int v){
        if(u != v){
            G[u].emplace_back(v);
            G[v].emplace_back(u);
        }
    }

    int build(){
        int n = G.size(), pos = 0;
        for (int i = 0; i < n; ++i) {
            if(ord[i] < 0) dfs(i, pos);
        }
        int k = 0;
        for (int i = 0; i < n; ++i) {
            if(!~bridge[i]){
                bridge[i] = k++;
                out.emplace_back();
                dfs2(i);
            }
        }
        return k;
    }
};

class UnionFind {
    int n;
    vector<int> uni;
    int forest_size;
public:
    explicit UnionFind(int n) : n(n), uni(static_cast<u32>(n), -1), forest_size(n) {};

    int root(int a){
        if (uni[a] < 0) return a;
        else return (uni[a] = root(uni[a]));
    }

    bool unite(int a, int b) {
        a = root(a);
        b = root(b);
        if(a == b) return false;
        if(uni[a] > uni[b]) swap(a, b);
        uni[a] += uni[b];
        uni[b] = a;
        forest_size--;
        return true;
    }
    int size(){ return forest_size; }
    int size(int i){ return -uni[root(i)]; }
    bool same(int a, int b) { return root(a) == root(b); }
};

int main() {
    int n, m;
    cin >> n >> m;
    TwoEdgeConnectedComponents G(n);
    for (int i = 0; i < m; ++i) {
        int a, b;
        scanf("%d %d", &a, &b);
        G.add_edge(a, b);
    }
    int k = G.build();
    vector<vector<int>> g(k);
    vector<int> v(k);
    UnionFind uf(k);
    for (int i = 0; i < k; ++i) v[i] = G.out[i].size();
    for (int i = 0; i < n; ++i) {
        for (auto &&j : G.G[i]) {
            if(G.is_bridge(i, j)){
                g[G.bridge[i]].emplace_back(G.bridge[j]);
                uf.unite(G.bridge[i], G.bridge[j]);
            }
        }
    }
    int ans = 0;
    vector<int> dp1(v), dp2(k);
    auto dfs = [&](int x, int par, auto &&f) -> void{
        for (auto &&y : g[x]) {
            if(y == par) continue;
            f(y, x, f);
            dp2[x] += max(dp1[y], dp2[y]);
            dp1[x] += dp2[y];
        }
    };
    for (int i = 0; i < k; ++i) {
        if(uf.root(i) == i) {
            dfs(i, -1, dfs);
            ans += max(dp1[i], dp2[i]);
        }
    }
    cout << ans << "\n";
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 23460
final_rank: 7

code_snippet: #define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0377"

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

#define call_from_test
#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename F>
struct FixPoint : F{
  FixPoint(F&& f):F(forward<F>(f)){}
  template<typename... Args>
  decltype(auto) operator()(Args&&... args) const{
    return F::operator()(*this,forward<Args>(args)...);
  }
};
template<typename F>
inline decltype(auto) MFP(F&& f){
  return FixPoint<F>{forward<F>(f)};
}
//END CUT HERE
#ifndef call_from_test
//INSERT ABOVE HERE
signed main(){
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
// work with multigraph
struct TwoEdgeConnectedComponents{
  vector<int> ord,low,par,blg,sz;
  vector<vector<int>> G,C;

  TwoEdgeConnectedComponents(int n):
    ord(n,-1),low(n),par(n,-1),blg(n,-1),sz(n,1),G(n){}

  void add_edge(int u,int v){
    if(u==v) return;
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  bool is_bridge(int u,int v){
    if(ord[u]>ord[v]) swap(u,v);
    return ord[u]<low[v];
  }

  void dfs(int v,int &pos){
    ord[v]=low[v]=pos++;
    int dup=0;
    for(int u:G[v]){
      if(u==par[v] and !dup){
        dup=1;
        continue;
      }
      if(~ord[u]){
        low[v]=min(low[v],ord[u]);
        continue;
      }
      par[u]=v;
      dfs(u,pos);
      sz[v]+=sz[u];
      low[v]=min(low[v],low[u]);
    }
  }

  void fill_component(int v){
    C[blg[v]].emplace_back(v);
    for(int u:G[v]){
      if(~blg[u]||is_bridge(u,v)) continue;
      blg[u]=blg[v];
      fill_component(u);
    }
  }

  void add_component(int v,int &k){
    if(~blg[v]) return;
    blg[v]=k++;
    C.emplace_back();
    fill_component(v);
  }

  int build(){
    int n=G.size(),pos=0;
    for(int i=0;i<n;i++)
      if(ord[i]<0) dfs(i,pos);

    int k=0;
    for(int i=0;i<n;i++) add_component(i,k);

    return k;
  }

  const vector<int>& operator[](int i)const{return C[i];}

  vector<vector<int>> forest(){
    int n=G.size(),k=C.size();
    vector<vector<int>> T(k);
    for(int v=0;v<n;v++)
      for(int u:G[v])
        if(blg[v]!=blg[u])
          T[blg[v]].emplace_back(blg[u]);
    return T;
  }
};
//END CUT HERE
#ifndef call_from_test
//INSERT ABOVE HERE
signed main(){
  return 0;
}
#endif

#undef call_from_test

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

  int n,m;
  cin>>n>>m;
  TwoEdgeConnectedComponents tecc(n);
  for(int i=0;i<m;i++){
    int a,b;
    cin>>a>>b;
    tecc.add_edge(a,b);
  }
  int k=tecc.build();
  auto G=tecc.forest();

  vector<int> cs(k);
  for(int i=0;i<k;i++) cs[i]=tecc[i].size();

  vector< vector<int> > dp(2,vector<int>(k,0));
  vector<int> used(k,0);
  auto dfs=
    MFP([&](auto dfs,int v,int p)->void{
          if(used[v]) return;
          used[v]=1;
          dp[0][v]=0;
          dp[1][v]=cs[v];
          for(int u:G[v]){
            if(u==p) continue;
            dfs(u,v);
            dp[0][v]+=max(dp[0][u],dp[1][u]);
            dp[1][v]+=dp[0][u];
          }
          return;
        });

  int ans=0;
  for(int i=0;i<k;i++){
    if(used[i]) continue;
    dfs(i,-1);
    ans+=max(dp[0][i],dp[1][i]);
  }
  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 22692
final_rank: 6

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

using ll = long long int;
using P = pair<int, int>;
using P3 = pair<int, P>;
using PP = pair<P, P>;
constexpr int INF = 1 << 30;
constexpr ll MOD = ll(1e9) + 7;
constexpr int di[] = {0, 1, 0, -1};
constexpr int dj[] = {1, 0, -1, 0};

struct UnionFindTree {
    int V;
    vector<int> par;
    vector<int> rank;
    vector<int> siz;

    void init(int n) {
        V = n;
        par.resize(n);
        rank.resize(n);
        siz.resize(n);
        for (int i = 0; i < n; i++) {
            par[i] = i;
            rank[i] = 0;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) {
            return x;
        } else {
            return par[x] = find(par[x]);
        }
    }
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        V--;
        if (rank[x] < rank[y]) swap(x, y);
        if (rank[x] == rank[y]) rank[x]++;
        par[y] = x;
        siz[x] += siz[y];
    }
    bool is_same(int x, int y) {
        return find(x) == find(y);
    }
    int size(int x) {
        x = find(x);
        return siz[x];
    }
};

int N, M;

vector<vector<int> > g, G;
vector<int> ord, low;
vector<bool> is_articulation, visited;
vector<P> bridges, non_bridges;

void dfs(int u, int par, int &k){
    ord[u] = k;
    k++;
    low[u] = ord[u];
    visited[u] = true;
    int cnt = 0;
    for(auto v : g[u]){
        // dfsの子ノードへ移動
        if(ord[v] == -1){
            cnt++;
            dfs(v, u, k);
            low[u] = min(low[u], low[v]);
            if(par!=-1 && ord[u] <= low[v]){
                is_articulation[u] = true;
            }
            if(ord[u] < low[v]){
                bridges.push_back(make_pair(min(u,v), max(u,v)));
            }else{
                non_bridges.push_back(make_pair(min(u,v), max(u,v)));
            }
        }
        // dfs木の後退辺を移動
        else if(v != par)low[u] = min(low[u], ord[v]);
    }
    if(par == -1){
        is_articulation[u] = cnt >= 2;  // 根はdfs木の次数が2以上ならば関節点
    }
}

void lowlink(){
    ord.assign(g.size(), -1);
    low.assign(g.size(), INF);
    visited.assign(g.size(), false);
    is_articulation.assign(g.size(), false);
    int k = 0;
    for(int i=0;i<int(g.size());i++){
        if(!visited[i]) dfs(i, -1, k);
    }
}

UnionFindTree uf;
map<int,int> id;
vector<int> val;
vector<vector<int> > dp;

int rec(int i, int c, int p){
    if(dp[i][c] != -1) return dp[i][c];
    visited[i] = true;
    int res = 0;
    for(auto &j : G[i]){
        if(j == p) continue;
        res += rec(j,1,i);
    }
    if(c == 1){
        int sum = val[i];
        for(auto &j : G[i]){
            if(j == p) continue;
            sum += rec(j,0,i); 
        }
        res = max(res, sum);
    }
    return dp[i][c] = res;
}

int main() {
    cin >> N >> M;
    g.resize(N);
    for(int i=0;i<M;i++){
        int s, t;
        cin >> s >> t;
        g[s].emplace_back(t);
        g[t].emplace_back(s);
    }
    lowlink();
    uf.init(N);
    for(auto &e : non_bridges){
        int s = e.first, t = e.second;
        uf.unite(s,t);
    }
    val.resize(uf.V);
    for(int i=0,idx=0;i<N;i++){
        if(id.find(uf.find(i))==id.end()){
            id[uf.find(i)] = idx;
            val[idx] = uf.size(i);
            idx++;
        }
    }
    G.resize(uf.V);
    for(auto &e : bridges){
        int s = uf.find(e.first), t = uf.find(e.second);
        G[id[s]].push_back(id[t]);
        G[id[t]].push_back(id[s]);
    }
    dp.resize(uf.V, vector<int>(2, -1));
    fill(visited.begin(), visited.end(), false);
    int ans = 0;
    for(int i=0;i<uf.V;i++){
        if(!visited[i]){
            ans += rec(i,1,-1);
        }
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 27012
final_rank: 17

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

using ll = long long int;
using P = pair<int, int>;
using P3 = pair<int, P>;
using PP = pair<P, P>;
constexpr int INF = 1 << 30;
constexpr ll MOD = ll(1e9) + 7;
constexpr int di[] = {0, 1, 0, -1};
constexpr int dj[] = {1, 0, -1, 0};

struct UnionFindTree {
    int V;
    vector<int> par;
    vector<int> rank;
    vector<int> siz;

    void init(int n) {
        V = n;
        par.resize(n);
        rank.resize(n);
        siz.resize(n);
        for (int i = 0; i < n; i++) {
            par[i] = i;
            rank[i] = 0;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) {
            return x;
        } else {
            return par[x] = find(par[x]);
        }
    }
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        V--;
        if (rank[x] < rank[y]) swap(x, y);
        if (rank[x] == rank[y]) rank[x]++;
        par[y] = x;
        siz[x] += siz[y];
    }
    bool is_same(int x, int y) {
        return find(x) == find(y);
    }
    int size(int x) {
        x = find(x);
        return siz[x];
    }
};

int N, M;

vector<vector<int> > g, G;
vector<int> ord, low;
vector<bool> is_articulation, visited;
vector<P> bridges, es;

void dfs(int u, int par, int &k){
    ord[u] = k;
    k++;
    low[u] = ord[u];
    visited[u] = true;
    int cnt = 0;
    for(auto v : g[u]){
        // dfsの子ノードへ移動
        if(ord[v] == -1){
            cnt++;
            dfs(v, u, k);
            low[u] = min(low[u], low[v]);
            if(par!=-1 && ord[u] <= low[v]){
                is_articulation[u] = true;
            }
            if(ord[u] < low[v]){
                bridges.push_back(make_pair(min(u,v), max(u,v)));
            }
        }
        // dfs木の後退辺を移動
        else if(v != par)low[u] = min(low[u], ord[v]);
    }
    if(par == -1){
        is_articulation[u] = cnt >= 2;  // 根はdfs木の次数が2以上ならば関節点
    }
}

void lowlink(){
    ord.assign(g.size(), -1);
    low.assign(g.size(), INF);
    visited.assign(g.size(), false);
    is_articulation.assign(g.size(), false);
    int k = 0;
    for(int i=0;i<int(g.size());i++){
        if(!visited[i]) dfs(i, -1, k);
    }
}

UnionFindTree uf;
map<int,int> id;
vector<int> val;
vector<vector<int> > dp;

int rec(int i, int c, int p){
    if(dp[i][c] != -1) return dp[i][c];
    visited[i] = true;
    int res = 0;
    for(auto &j : G[i]){
        if(j == p) continue;
        res += rec(j,1,i);
    }
    if(c == 1){
        int sum = val[i];
        for(auto &j : G[i]){
            if(j == p) continue;
            sum += rec(j,0,i); 
        }
        res = max(res, sum);
    }
    return dp[i][c] = res;
}

int main() {
    cin >> N >> M;
    g.resize(N);
    for(int i=0;i<M;i++){
        int s, t;
        cin >> s >> t;
        g[s].emplace_back(t);
        g[t].emplace_back(s);
        es.push_back(P(s,t));
    }
    lowlink();
    uf.init(N);
    for(auto &e : es){
        int s = e.first, t = e.second;
        if(low[s] == low[t]){
            uf.unite(s,t);
        }
    }
    val.resize(uf.V);
    for(int i=0,idx=0;i<N;i++){
        if(id.find(uf.find(i))==id.end()){
            id[uf.find(i)] = idx;
            val[idx] = uf.size(i);
            idx++;
        }
    }
    G.resize(uf.V);
    for(auto &e : bridges){
        int s = uf.find(e.first), t = uf.find(e.second);
        G[id[s]].push_back(id[t]);
        G[id[t]].push_back(id[s]);
    }
    dp.resize(uf.V, vector<int>(2, -1));
    fill(visited.begin(), visited.end(), false);
    int ans = 0;
    for(int i=0;i<uf.V;i++){
        if(!visited[i]){
            ans += rec(i,1,-1);
        }
    }
    cout << ans << endl;
    return 0;
}
accuracy: 0.6333333333333333
time_ms: 30
memory_kb: 17872
final_rank: 19

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

using ll = long long int;
using P = pair<int, int>;
using P3 = pair<int, P>;
using PP = pair<P, P>;
constexpr int INF = 1 << 30;
constexpr ll MOD = ll(1e9) + 7;
constexpr int di[] = {0, 1, 0, -1};
constexpr int dj[] = {1, 0, -1, 0};

struct UnionFindTree {
    int N;
    vector<int> par;
    vector<int> rank;
    vector<int> siz;

    void init(int n) {
        N = n;
        par.resize(n);
        rank.resize(n);
        siz.resize(n);
        for (int i = 0; i < n; i++) {
            par[i] = i;
            rank[i] = 0;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) {
            return x;
        } else {
            return par[x] = find(par[x]);
        }
    }
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        N--;
        if (rank[x] < rank[y]) swap(x, y);
        if (rank[x] == rank[y]) rank[x]++;
        par[y] = x;
        siz[x] += siz[y];
    }
    bool is_same(int x, int y) {
        return find(x) == find(y);
    }
    int size(int x) {
        x = find(x);
        return siz[x];
    }
};

int N, M;

vector<vector<int> > g, G;
vector<int> ord, low;
vector<bool> is_articulation, visited;
vector<P> bridges, es;

void dfs(int u, int par, int &k){
    ord[u] = k;
    k++;
    low[u] = ord[u];
    visited[u] = true;
    int cnt = 0;
    for(auto v : g[u]){
        // dfsの子ノードへ移動
        if(ord[v] == -1){
            cnt++;
            dfs(v, u, k);
            low[u] = min(low[u], low[v]);
            if(par!=-1 && ord[u] <= low[v]){
                is_articulation[u] = true;
            }
            if(ord[u] < low[v]){
                bridges.push_back(make_pair(min(u,v), max(u,v)));
            }
        }
        // dfs木の後退辺を移動
        else if(v != par)low[u] = min(low[u], ord[v]);
    }
    if(par == -1){
        is_articulation[u] = cnt >= 2;  // 根はdfs木の次数が2以上ならば関節点
    }
}

void lowlink(){
    ord.resize(g.size(), -1);
    low.resize(g.size());
    visited.resize(g.size(), false);
    is_articulation.resize(g.size(), false);
    int k = 0;
    for(int i=0;i<int(g.size());i++){
        if(!visited[i]) dfs(i, -1, k);
    }
}

UnionFindTree uf;
map<int,int> id;
vector<int> val;
vector<vector<int> > dp;

int rec(int i, int c, int p){
    if(dp[i][c] != -1) return dp[i][c];
    visited[i] = true;
    int res = 0;
    for(auto &j : G[i]){
        if(j == p) continue;
        res += rec(j,1,i);
    }
    if(c == 1){
        int sum = val[i];
        for(auto &j : G[i]){
            if(j == p) continue;
            sum += rec(j,0,i); 
        }
        res = max(res, sum);
    }
    return dp[i][c] = res;
}

int main() {
    cin >> N >> M;
    g.resize(N);
    for(int i=0;i<M;i++){
        int s, t;
        cin >> s >> t;
        g[s].emplace_back(t);
        g[t].emplace_back(s);
        es.push_back(P(s,t));
    }
    lowlink();
    uf.init(N);
    for(auto &e : es){
        int s = e.first, t = e.second;
        if(low[s] == low[t]){
            uf.unite(s,t);
        }
    }
    val.resize(uf.N);
    for(int i=0,idx=0;i<N;i++){
        if(id.find(uf.find(i))==id.end()){
            id[uf.find(i)] = idx;
            val[idx] = uf.size(i);
            idx++;
        }
    }
    G.resize(uf.N);
    for(auto &e : bridges){
        int s = uf.find(e.first), t = uf.find(e.second);
        G[id[s]].push_back(id[t]);
        G[id[t]].push_back(id[s]);
    }
    dp.resize(uf.N, vector<int>(2, -1));
    fill(visited.begin(), visited.end(), false);
    int ans = 0;
    for(int i=0;i<uf.N;i++){
        if(!visited[i]){
            ans += rec(i,1,-1);
        }
    }
    cout << ans << endl;
    return 0;
}
accuracy: 0.6333333333333333
time_ms: 40
memory_kb: 17864
final_rank: 20

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

using ll = long long int;
using P = pair<int, int>;
using P3 = pair<int, P>;
using PP = pair<P, P>;
constexpr int INF = 1 << 30;
constexpr ll MOD = ll(1e9) + 7;
constexpr int di[] = {0, 1, 0, -1};
constexpr int dj[] = {1, 0, -1, 0};

struct UnionFindTree {
    int N;
    vector<int> par;
    vector<int> rank;
    vector<int> siz;

    void init(int n) {
        N = n;
        par.resize(n);
        rank.resize(n);
        siz.resize(n);
        for (int i = 0; i < n; i++) {
            par[i] = i;
            rank[i] = 0;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) {
            return x;
        } else {
            return par[x] = find(par[x]);
        }
    }
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        N--;
        if (rank[x] < rank[y]) swap(x, y);
        if (rank[x] == rank[y]) rank[x]++;
        par[y] = x;
        siz[x] += siz[y];
    }
    bool is_same(int x, int y) {
        return find(x) == find(y);
    }
    int size(int x) {
        x = find(x);
        return siz[x];
    }
};

int N, M;

vector<vector<int> > g, G;
vector<int> ord, low;
vector<bool> is_articulation, visited;
vector<P> bridges, es;

void dfs(int u, int par, int &k){
    ord[u] = k;
    k++;
    low[u] = ord[u];
    visited[u] = true;
    int cnt = 0;
    for(auto v : g[u]){
        // dfsの子ノードへ移動
        if(ord[v] == -1){
            cnt++;
            dfs(v, u, k);
            low[u] = min(low[u], low[v]);
            if(par!=-1 && ord[u] <= low[v]){
                is_articulation[u] = true;
            }
            if(ord[u] < low[v]){
                bridges.push_back(make_pair(min(u,v), max(u,v)));
            }
        }
        // dfs木の後退辺を移動
        else if(v != par)low[u] = min(low[u], ord[v]);
    }
    if(par == -1){
        is_articulation[u] = cnt >= 2;  // 根はdfs木の次数が2以上ならば関節点
    }
}

void lowlink(){
    ord.resize(g.size(), -1);
    low.resize(g.size());
    visited.resize(g.size(), false);
    is_articulation.resize(g.size(), false);
    int k = 0;
    for(int i=0;i<int(g.size());i++){
        if(!visited[i]) dfs(i, -1, k);
    }
}

UnionFindTree uf;
map<int,int> id;
vector<int> val;
vector<vector<int> > dp;

int rec(int i, int c, int p){
    if(dp[i][c] != -1) return dp[i][c];
    visited[i] = true;
    int res = 0;
    for(auto &j : G[i]){
        if(j == p) continue;
        res += rec(j,1,i);
    }
    if(c == 1){
        int sum = val[i];
        for(auto &j : G[i]){
            if(j == p) continue;
            sum += rec(j,0,i); 
        }
        res = max(res, sum);
    }
    return dp[i][c] = res;
}

int main() {
    cin >> N >> M;
    g.resize(N);
    for(int i=0;i<M;i++){
        int s, t;
        cin >> s >> t;
        g[s].emplace_back(t);
        g[t].emplace_back(s);
        es.push_back(P(s,t));
    }
    lowlink();
    uf.init(N);
    for(auto &e : es){
        int s = e.first, t = e.second;
        if(low[s] == low[t]){
            uf.unite(s,t);
        }
    }
    val.resize(uf.N);
    for(int i=0,idx=0;i<N;i++){
        if(id.find(uf.find(i))==id.end()){
            id[uf.find(i)] = idx;
            val[idx] = uf.size(i);
            idx++;
        }
    }
    G.resize(uf.N);
    for(auto &e : bridges){
        int s = uf.find(e.first), t = uf.find(e.second);
        G[id[s]].push_back(id[t]);
        G[id[t]].push_back(id[s]);
    }
    dp.resize(uf.N, vector<int>(2, -1));
    visited.assign(uf.N, false);
    int ans = 0;
    for(int i=0;i<uf.N;i++){
        if(!visited[i]){
            ans += rec(i,1,-1);
        }
    }
    cout << ans << endl;
    return 0;
}
accuracy: 0.6333333333333333
time_ms: 30
memory_kb: 17780
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=long long;
using ld=long double;
using ull=unsigned long long;
using uint=unsigned int;
using pcc=pair<char,char>;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
using pdd=pair<double,double>;
using tuplis=pair<ll,pll>;
using tuplis2=pair<pll,ll>;
template<class T> using pq=priority_queue<T,vector<T>,greater<T>>;
const ll LINF=0x1fffffffffffffff;
const ll MINF=0x7fffffffffff;
const int INF=0x3fffffff;
const ll MOD=1000000007;
const ll MODD=998244353;
const ld DINF=numeric_limits<ld>::infinity();
const ld EPS=1e-9;
const ld PI=3.141592653589793238462643383279;
const vector<ll>four{0,1,0,-1,0};
#define _overload4(_1,_2,_3,_4,name,...) name
#define _overload3(_1,_2,_3,name,...) name
#define _rep1(n) for(ll i=0;i<n;++i)
#define _rep2(i,n) for(ll i=0;i<n;++i)
#define _rep3(i,a,b) for(ll i=a;i<b;++i)
#define _rep4(i,a,b,c) for(ll i=a;i<b;i+=c)
#define rep(...) _overload4(__VA_ARGS__,_rep4,_rep3,_rep2,_rep1)(__VA_ARGS__)
#define _rrep1(n) for(ll i=(n)-1;i>=0;i--)
#define _rrep2(i,n) for(ll i=(n)-1;i>=0;i--)
#define _rrep3(i,a,b) for(ll i=(b)-1;i>=(a);i--)
#define _rrep4(i,a,b,c) for(ll i=a+(b-a-1)/c*c;i>=a;i-=c)
#define rrep(...) _overload4(__VA_ARGS__,_rrep4,_rrep3,_rrep2,_rrep1)(__VA_ARGS__)
#define each(i,a) for(auto &i:a)
#define sum(...) accumulate(range(__VA_ARGS__),0LL)
#define dsum(...) accumulate(range(__VA_ARGS__),double(0))
#define _range(i) (i).begin(),(i).end()
#define _range2(i,k) (i).begin(),(i).begin()+k
#define _range3(i,a,b) (i).begin()+a,(i).begin()+b
#define range(...) _overload3(__VA_ARGS__,_range3,_range2,_range)(__VA_ARGS__)
#define _rrange(i) (i).rbegin(),(i).rend()
#define _rrange2(i,k) (i).rbegin(),(i).rbegin()+k
#define _rrange3(i,a,b) (i).rbegin()+a,(i).rbegin()+b
#define rrange(...) _overload3(__VA_ARGS__,_rrange3,_rrange2,_rrange)(__VA_ARGS__)
#define elif else if
#define unless(a) if(!(a))
#define mp make_pair
#define mt make_tuple
#define INT(...) int __VA_ARGS__;in(__VA_ARGS__)
#define LL(...) ll __VA_ARGS__;in(__VA_ARGS__)
#define ULL(...) ull __VA_ARGS__;in(__VA_ARGS__)
#define STR(...) string __VA_ARGS__;in(__VA_ARGS__)
#define CHR(...) char __VA_ARGS__;in(__VA_ARGS__)
#define DBL(...) double __VA_ARGS__;in(__VA_ARGS__)
#define vec(type,name,...) vector<type> name(__VA_ARGS__)
#define VEC(type,name,size) vector<type> name(size);in(name)
#define vv(type,name,h,...) vector<vector<type>>name(h,vector<type>(__VA_ARGS__))
#define VV(type,name,h,...) vector<vector<type>>name(h,vector<type>(__VA_ARGS__));in(name)
#define vvv(type,name,h,w,...) vector<vector<vector<type>>>name(h,vector<vector<type>>(w,vector<type>(__VA_ARGS__)))
inline constexpr ll gcd(ll a,ll b){while(b){ll c=b;b=a%b;a=c;}return a;}
inline constexpr ll lcm(ll a,ll b){if(!a||!b)return 0;return a*b/gcd(a,b);}
template<class T> inline constexpr T min(vector<T> &v){return *min_element(range(v));}
inline char min(string &v){return *min_element(range(v));}
template<class T> inline constexpr T max(vector<T> &v){return *max_element(range(v));}
inline char max(string &v){return *max_element(range(v));}
inline constexpr ll intpow(ll a,ll b){ll ans=1;for(ll i=1;b;i*=2){if(b&i){b^=i;ans*=a;}a*=a;}return ans;}
template<typename T>
inline constexpr bool chmin(T &mn,const T &cnt){if(mn>cnt){mn=cnt;return 1;}else return 0;}
template<typename T>
inline constexpr bool chmax(T &mx,const T &cnt){if(mx<cnt){mx=cnt;return 1;}else return 0;}
template<class T> unordered_map<T,ll> press(vector<T> &a){ auto b = a; sort(range(b)); b.erase(unique(range(b)), b.end()); unordered_map<T,ll> ans; rep(b.size()) ans[b[i]] = i; each(i, a) i = ans[i]; return ans; }
template<class T> map<T,ll> press_map(vector<T> &a){ auto b = a; sort(range(b)); b.erase(unique(range(b)), b.end()); map<T,ll> ans; rep(b.size()) ans[b[i]] = i; each(i, a) i = ans[i]; return ans; }
inline int scan(){ return getchar(); }
inline void scan(int &a){ scanf("%d", &a); }
inline void scan(unsigned &a){ scanf("%u", &a); }
inline void scan(long &a){ scanf("%ld", &a); }
inline void scan(long long &a){ scanf("%lld", &a); }
inline void scan(unsigned long long &a){ scanf("%llu", &a); }
inline void scan(char &a){ cin >> a; }
inline void scan(float &a){ scanf("%f", &a); }
inline void scan(double &a){ scanf("%lf", &a); }
inline void scan(long double &a){ scanf("%Lf", &a); }
inline void scan(vector<bool> &vec){ for(unsigned i = 0; i < vec.size(); i++) { int a; scan(a); vec[i] = a; } }
inline void scan(char a[]){ scanf("%s", a); }
inline void scan(string &a){ cin >> a; }
template<class T> inline void scan(vector<T> &vec);
template<class T, size_t size> inline void scan(array<T, size> &vec);
template<class T, class L> inline void scan(pair<T, L> &p);
template<class T, size_t size> inline void scan(T (&vec)[size]);
template<class T> inline void scan(vector<T> &vec){ for(auto &i : vec) scan(i); }
template<class T, size_t size> inline void scan(array<T, size> &vec){ for(auto &i : vec) scan(i); }
template<class T, class L> inline void scan(pair<T, L> &p){ scan(p.first); scan(p.second); }
template<class T, size_t size> inline void scan(T (&vec)[size]){ for(auto &i : vec) scan(i); }
template<class T> inline void scan(T &a){ cin>>a; }
inline void in(){}
template <class Head, class... Tail> inline void in(Head &head, Tail&... tail){ scan(head); in(tail...); }
inline void print(){ putchar(' '); }
inline void print(const bool &a){ printf("%d", a); }
inline void print(const int &a){ printf("%d", a); }
inline void print(const unsigned &a){ printf("%u", a); }
inline void print(const long &a){ printf("%ld", a); }
inline void print(const long long &a){ printf("%lld", a); }
inline void print(const unsigned long long &a){ printf("%llu", a); }
inline void print(const char &a){ printf("%c", a); }
inline void print(const char a[]){ printf("%s", a); }
inline void print(const float &a){ printf("%.15f", a); }
inline void print(const double &a){ printf("%.15f", a); }
inline void print(const long double &a){ printf("%.15Lf", a); }
inline void print(const string &a){ each(i, a) print(i); }
template<class T> void print(const vector<T> &vec);
template<class T, size_t size> void print(const array<T, size> &vec);
template<class T, class L> void print(const pair<T, L> &p);
template<class T, size_t size> inline void print(const T (&vec)[size]);
template<class T> void print(const vector<T> &vec){ if(vec.empty()) return; print(vec[0]); for(auto i = vec.begin(); ++i != vec.end(); ){ putchar(' '); print(*i); } }
template<class T, size_t size> void print(const array<T, size> &vec){ print(vec[0]); for(auto i = vec.begin(); ++i != vec.end(); ){ putchar(' '); print(*i); } }
template<class T, class L> void print(const pair<T, L> &p){ print(p.first); putchar(' '); print(p.second); }
template<class T, size_t size> inline void print(const T (&vec)[size]){ print(vec[0]); for(auto i = vec; ++i != end(vec); ){ putchar(' '); print(*i); } }
template<class T> inline void print(const T &a){ cout << a; }
inline int out(){ putchar('\n'); return 0; }
template<class T> inline int out(const T &t){ print(t); putchar('\n'); return 0; }
template<class Head, class... Tail> inline int out(const Head &head, const Tail&... tail){ print(head); putchar(' '); out(tail...); return 0; }
template <class T> inline void err(T t){cerr<<t<<'\n';}
template<class Head, class... Tail> inline void err(const Head &head, const Tail&... tail){ cerr<<head<<' '; err(tail...); }
inline void err(){cerr<<'\n';}
inline int first(const bool &i){return out(i?"first":"second");}
inline int yes(const bool &i){return out(i?"yes":"no");}
inline int Yes(const bool &i){return out(i?"Yes":"No");}
inline int YES(const bool &i){return out(i?"YES":"NO");}
inline int Yay(const bool &i){return out(i?"Yay!":":(");}
inline int Possible(const bool &i){return out(i?"Possible":"Impossible");}
inline int POSSIBLE(const bool &i){return out(i?"POSSIBLE":"IMPOSSIBLE");}
inline void Case(ll i){printf("Case #%lld: ",i);}


struct UnionFind{
    vector<ll>data;
    UnionFind(ll n):data(n,-1){}
    bool unite(ll a,ll b){
        a=root(a);b=root(b);
        if(a==b)return 1;
        if(data[a]>data[b])swap(a,b);
        data[a]+=data[b];
        data[b]=a;
        return 0;
    }
    bool find(ll a,ll b){return root(a)==root(b);}
    ll root(ll a){return data[a]<0?a:data[a]=root(data[a]);}
    ll size(ll a){return -data[root(a)];}
    ll operator[](ll a){return root(a);}
};
struct BiConnected{
    ll cnt = 0, n;
    const vector<vector<ll>>& _g;
    vector<vector<ll>> g;
    vector<ll> low, pre, id, siz;
    UnionFind uf;
    BiConnected(const vector<vector<ll>>& _g): n(_g.size()), _g(_g), low(n), pre(n, LINF), id(n), uf(n){
        dfs(-1, 0);
        cnt = 0;
        rep(n) if(uf.data[i] < 0) id[i] = cnt++;
        siz.resize(cnt);
        rep(n){
            id[i] = id[uf[i]];
            siz[id[i]]++;
        }
        g.resize(cnt);
        rep(n) each(j, _g[i]) if(id[i] != id[j]) g[id[i]].push_back(id[j]);
    }
    void dfs(ll from, ll at){
        pre[at] = low[at] = cnt++;
        each(i, _g[at]) if(i != from){
            if(pre[i] == LINF) dfs(at, i);
            chmin(low[at], low[i]);
            if(low[i] != pre[i]) uf.unite(at, i);
        }
    }
    ll size(){ return cnt; }
    ll size(ll x){ return siz[x]; }
    vector<ll>& operator[](ll x){ return g[x]; }
    operator vector<vector<ll>>&(){ return g; }
};
signed main(){
    LL(n, m);
    vector<vector<ll>> g(n), a(n);
    UnionFind uf(n);
    rep(m){
        LL(a, b);
        g[a].push_back(b);
        g[b].push_back(a);
        uf.unite(a, b);
    }
    rep(n) a[uf[i]].push_back(i);
    ll ans = 0;
    each(v, a) if(v.size()){
        ll cnt = 0;
        unordered_map<ll,ll> press;
        each(i, v) press[i] = cnt++;
        vector<vector<ll>> gg(v.size());
        rep(i, v.size()) each(k, g[v[i]]) gg[i].push_back(press[k]);
        BiConnected g(gg);
        vv(ll, dp, g.size(), 2);
        auto dfs=[&g, &dp](ll from, ll at, auto& f) -> void {
            dp[at][1] += g.size(at);
            each(i,g[at])if(i!=from){
                f(at, i, f);
                dp[at][1] += dp[i][0];
                dp[at][0] += max(dp[i]);
            }
        };
        dfs(-1, 0, dfs);
        ans += max(dp[0]);
    }
    out(ans);
}
accuracy: 1
time_ms: 80
memory_kb: 38292
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
template<typename G>
struct LowLink {
    const G &g;
    vector<int> used, ord, low;
    vector<int> articulation;
    vector<pair<int, int> > bridge;
    LowLink(const G &g):g(g) {};
    int dfs(int idx, int k, int par) {
        used[idx] = true;
        ord[idx] = k++;
        low[idx] = ord[idx];
        bool is_articulation = false;
        int cnt = 0;
        for (auto &to : g[idx]) {
            if (!used[to]) {
                ++cnt;
                k = dfs(to, k, idx);
                low[idx] = min(low[idx], low[to]);
                is_articulation |= ~par && low[to] >= ord[idx];
                if (ord[idx] < low[to]) bridge.emplace_back(minmax(idx, (int)to));
            } else if (to != par) {
                low[idx] = min(low[idx], ord[to]);
            }
        }
        is_articulation |= par == -1 && cnt > 1;
        if (is_articulation) articulation.push_back(idx);
        return k;
    };
    virtual void build() {
        used.assign(g.size(), 0);
        ord.assign(g.size(), 0);
        low.assign(g.size(), 0);
        int k = 0;
        for (int i = 0; i < g.size(); i++) {
            if (!used[i]) k = dfs(i, k, -1);
        }
    };
};
template<typename G>
struct TwoEdgeConnectComponents : LowLink<G> {
    using LL = LowLink<G>;
    vector<int> comp;
    TwoEdgeConnectComponents(const G &g) : LL(g) {};
    int operator[] (const int &k) {
        return comp[k];
    };
    void dfs(int idx, int par, int &k) {
        if (~par && this->ord[par] >= this->low[idx]) comp[idx] = comp[par];
        else comp[idx] = k++;
        for (auto &to : this->g[idx]) {
            if (comp[to] == -1) dfs(to, idx, k);
        }
    };
    void build(G &t) {
        LL::build();
        comp.assign(this->g.size(), -1);
        int k = 0;
        for (int i = 0; i < comp.size(); i++) {
            if (comp[i] == -1) dfs(i, -1, k);
        }
        t.resize(k);
        for (auto &e : this->bridge) {
            int x = comp[e.first], y = comp[e.second];
            t[x].push_back(y);
            t[y].push_back(x);
        }
    }
};
vector<vector<int> > g;
vector<vector<int> > t;
int node_sum[100005];
int memo[100010][2];
int dp(int i, int par){
    for(auto e : t[i]){
        if(e != par) dp(e, i);
    }
    int n1 = 0;
    int n2 = node_sum[i];
    for(auto e : t[i]){
        if(e == par) continue;
        n1 += max(memo[e][0], memo[e][1]);
        n2 += memo[e][0];
    }
    memo[i][0] = n1;
    memo[i][1] = n2;

    return max(n1, n2);
}

int main() {
    int n, m;
    cin >> n >> m;
    
    g.resize(n);
    for (int i = 0; i < m; i++) {
        int s, t;
        cin >> s >> t;
        g[s].push_back(t);
        g[t].push_back(s);
    }
    TwoEdgeConnectComponents<vector<vector<int> > > bcc(g);
    bcc.build(t);
    
    for (int i = 0; i < n; i++) {
        int u = bcc[i];
        node_sum[u]++;
    }
    
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int u = bcc[i];
        if (memo[u][0] == 0 && memo[u][1] == 0) {
            ans += dp(u, -1);
        }
    }

    cout << ans << endl;
}
accuracy: 1
time_ms: 60
memory_kb: 17608
final_rank: 4

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

using UnWeightedGraph = vector<vector<int>>;
struct LowLink {
    const UnWeightedGraph &g;
    vector<int> aps;                // articulation points
    vector<pair<int, int>> brs;     // brides
    vector<int> seen, ord, low;
    LowLink(const UnWeightedGraph &g) : g(g) { }
    int dfs(int u, int p = -1, int time = 0) {
        seen[u] = true;
        ord[u] = low[u] = time++;
        bool exists = false;
        int cnt_ch = 0;
        for (int v: g[u]) {
            if (!seen[v]) {
                ++cnt_ch;
                time = dfs(v, u, time);
                low[u] = min(low[u], low[v]);   // forward edge
                if (ord[u] < low[v]) brs.emplace_back(u, v);
                if (ord[u] <= low[v]) exists = true;
            } else if (v != p) {
                low[u] = min(low[u], ord[v]);   // back edge
            }
        }
        if ((p == -1 && cnt_ch > 1) || (p != -1 && exists)) aps.emplace_back(u);
        return time;
    }
    void build() {
        int N = g.size();
        seen.assign(N, 0); ord.resize(N); low.resize(N);
        aps.clear(); brs.clear();
        for (int v = 0; v < N; ++v) if (!seen[v]) dfs(v);
        for (auto &br: brs) if (br.first > br.second) swap(br.first, br.second);
        sort(brs.begin(), brs.end());
        sort(aps.begin(), aps.end());
    }
};
struct TwoEdgeConnectedComponents : LowLink {
    using LL = LowLink;
    vector<int> comp;
    TwoEdgeConnectedComponents(const UnWeightedGraph &g) : LL(g) { }
    int operator[](int k) { return comp[k]; }
    void dfs(int u, int p, int &k) {
        if (~p && this->ord[p] >= this->low[u]) comp[u] = comp[p];
        else comp[u] = k++;
        for (int v: this->g[u]) if (comp[v] == -1) dfs(v, u, k);
    }
    UnWeightedGraph build() {
        LL::build();
        comp.assign(this->g.size(), -1);
        int k = 0;
        for (int i = 0; i < comp.size(); ++i) if (comp[i] == -1) dfs(i, -1, k);
        UnWeightedGraph t_comp(k);
        for (auto &e: this->brs) {
            int x = comp[e.first], y = comp[e.second];
            t_comp[x].emplace_back(y);
            t_comp[y].emplace_back(x);
        }
        return t_comp;
    }
};

UnWeightedGraph tree;
vector<int> size;
vector<vector<int>> dp;
void dfs(int u, int p) {
    dp[0][u] = 0;
    dp[1][u] = size[u];
    for (int v: tree[u]) if (v != p) {
        dfs(v, u);
        dp[0][u] += max(dp[0][v], dp[1][v]);
        dp[1][u] += dp[0][v];
    }
}
int main() {
    int N, M; cin >> N >> M;
    UnWeightedGraph g(N);
    for (int i = 0; i < M; i++) {
        int s, t; cin >> s >> t;
        g[s].emplace_back(t);
        g[t].emplace_back(s);
    }
    TwoEdgeConnectedComponents bcc(g);
    tree = bcc.build();
    int V = tree.size();
    size.assign(V, 0);
    for (int i = 0; i < N; i++) size[bcc[i]]++;
    int ans = 0;
    dp.assign(2, vector<int>(V, -1));
    for (int i = 0; i < V; i++) if (dp[0][i] == -1) {   // 森
        dfs(i, -1);
        ans += max(dp[0][i], dp[1][i]);
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 17868
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
//BEGIN CUT HERE
struct LowLink{
  int n,pos;
  vector<int> ord,low,par,blg,num;
  vector<vector<int> > G,C,T;
  vector<vector<pair<int, int> > > E;
  
  vector<int> ap;
  vector<pair<int, int> > bs,cand;

  LowLink(int n):n(n),pos(0),ord(n,-1),low(n),
                 par(n,-1),blg(n,-1),num(n,1),G(n){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  bool is_bridge(int u,int v){
    if(ord[u]>ord[v]) swap(u,v);
    return ord[u]<low[v];
  }

  void dfs(int v){
    ord[v]=low[v]=pos++;
    for(int u:G[v]){
      if(u==par[v]) continue;      
      if(ord[u]<ord[v])
        cand.emplace_back(min(u,v),max(u,v));      
      if(~ord[u]){
        low[v]=min(low[v],ord[u]);
        continue;
      }
      par[u]=v;
      dfs(u);
      num[v]+=num[u];
      low[v]=min(low[v],low[u]);
      if(is_bridge(u,v)) bs.emplace_back(u,v);
      if(low[u]>=ord[v]){
        E.emplace_back();
        while(1){
          auto e=cand.back();
          cand.pop_back();
          E.back().emplace_back(e);
          if(make_pair(min(u,v),max(u,v))==e) break;          
        }
      }
    }
  }

  void fill_component(int v){
    C[blg[v]].emplace_back(v);
    for(int u:G[v]){
      if(~blg[u]||is_bridge(u,v)) continue;
      blg[u]=blg[v];
      fill_component(u);
    }
  }

  void add_component(int v,int &k){
    if(~blg[v]) return;
    blg[v]=k++;
    C.emplace_back();
    fill_component(v);
  }
  
  int build(){
    for(int i=0;i<n;i++)
      if(ord[i]<0) dfs(i);
    
    vector<int> cnt(n,0);
    for(int i=0;i<n;i++){
      int p=par[i];
      if(p<0) continue;
      if(par[p]<0) cnt[p]++;
      else if(ord[p]<=low[i]) ap.emplace_back(p);
    }
    
    for(int i=0;i<n;i++)
      if(cnt[i]>1) ap.emplace_back(i);

    sort(ap.begin(),ap.end());
    ap.erase(unique(ap.begin(),ap.end()),ap.end());

    int k=0;    
    for(int i=0;i<n;i++) add_component(i,k);

    T.assign(k,vector<int>());    
    for(auto e:bs){
      int u=blg[e.first],v=blg[e.second];
      T[u].emplace_back(v);
      T[v].emplace_back(u);
    }
    return k;
  }
};
//END CUT HERE

struct UnionFind{
  int n,num;
  vector<int> r,p;
  UnionFind(){}
  UnionFind(int sz):n(sz),num(sz),r(sz,1),p(sz,0){iota(p.begin(),p.end(),0);}
  int find(int x){
    return (x==p[x]?x:p[x]=find(p[x]));
  }
  bool same(int x,int y){
    return find(x)==find(y);
  }
  void unite(int x,int y){
    x=find(x);y=find(y);
    if(x==y) return;
    if(r[x]<r[y]) swap(x,y);
    r[x]+=r[y];
    p[y]=x;
    num--;
  }
  int size(int x){
    return r[find(x)];
  }
  int count() const{
    return num;
  }
};

template<typename T,T MOD = 1000000007>
struct Mint{
  T v;
  Mint():v(0){}
  Mint(signed v):v(v){}
  Mint(long long t){v=t%MOD;if(v<0) v+=MOD;}

  Mint pow(long long k){
    Mint res(1),tmp(v);
    while(k){
      if(k&1) res*=tmp;
      tmp*=tmp;
      k>>=1;
    }
    return res;
  }
  
  static Mint add_identity(){return Mint(0);}
  static Mint mul_identity(){return Mint(1);}
  
  Mint inv(){return pow(MOD-2);}
  
  Mint& operator+=(Mint a){v+=a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator-=(Mint a){v+=MOD-a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator*=(Mint a){v=1LL*v*a.v%MOD;return *this;}
  Mint& operator/=(Mint a){return (*this)*=a.inv();}
  
  Mint operator+(Mint a) const{return Mint(v)+=a;};
  Mint operator-(Mint a) const{return Mint(v)-=a;};
  Mint operator*(Mint a) const{return Mint(v)*=a;};
  Mint operator/(Mint a) const{return Mint(v)/=a;};

  Mint operator-() const{return v?Mint(MOD-v):Mint(v);}

  bool operator==(const Mint a)const{return v==a.v;}
  bool operator!=(const Mint a)const{return v!=a.v;}
  bool operator <(const Mint a)const{return v <a.v;}
};


template<typename M>
struct Enumeration{
  static vector<M> fact,finv,invs;
  
  static void init(int n){
    int m=fact.size();
    if(n<m) return;
    
    fact.resize(n+1,1);
    finv.resize(n+1,1);
    invs.resize(n+1,1);
    
    if(m==0) m=1;
    for(int i=m;i<=n;i++) fact[i]=fact[i-1]*M(i);
    finv[n]=M(1)/fact[n];
    for(int i=n;i>=m;i--) finv[i-1]=finv[i]*M(i);
    for(int i=m;i<=n;i++) invs[i]=finv[i]*fact[i-1];
  }
  
  static M C(int n,int k){
    if(n<k||k<0) return M(0);
    init(n);
    return fact[n]*finv[n-k]*finv[k];
  }
  
  static M H(int n,int k){
    if(n<0||k<0) return M(0);
    if(!n&&!k) return M(1);
    init(n+k-1);
    return C(n+k-1,k);
  }
};
template<typename M>
vector<M> Enumeration<M>::fact = vector<M>();
template<typename M>
vector<M> Enumeration<M>::finv = vector<M>();
template<typename M>
vector<M> Enumeration<M>::invs = vector<M>();

//INSERT ABOVE HERE
signed GRL_3_A(){
  int n,m;
  scanf("%d %d",&n,&m);
  LowLink G(n);
  for(int i=0;i<m;i++){
    int u,v;
    scanf("%d %d",&u,&v);
    G.add_edge(u,v);
  }
  G.build();
  auto ap=G.ap;
  sort(ap.begin(),ap.end());
  for(int v:ap) printf("%d\n",v);
  return 0;
}
/*
  verified on 2019/05/29
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_3_A&lang=jp
*/

signed GRL_3_B(){
  int n,m;
  scanf("%d %d",&n,&m);
  
  LowLink G(n);
  for(int i=0;i<m;i++){
    int u,v;
    scanf("%d %d",&u,&v);
    G.add_edge(u,v);
  }
  G.build();
  
  auto bs=G.bs;
  for(auto &e:bs)
    if(e.first>e.second) swap(e.first, e.second);
  
  sort(bs.begin(),bs.end());
  for(auto e:bs) printf("%d %d\n",e.first, e.second);
  
  return 0;
}
/*
  verified on 2019/03/23
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_3_B&lang=jp
*/

signed AOJ_0377(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  
  int n,m;
  cin>>n>>m;
  LowLink bg(n);
  for(int i=0;i<m;i++){
    int a,b;
    cin>>a>>b;
    bg.add_edge(a,b);
  }
  int k=bg.build();
  auto& G=bg.T;
  
  vector<int> c(k);
  for(int i=0;i<k;i++) c[i]=bg.C[i].size();
  vector<vector<int> > dp(2,vector<int>(k,0));
  vector<int> used(k,0);
  function<void(int,int)> dfs=[&](int v,int p){
    if(used[v]) return;
    used[v]=1;
    dp[0][v]=0;
    dp[1][v]=c[v];
    for(int u:G[v]){
      if(u==p) continue;
      dfs(u,v);
      dp[0][v]+=max(dp[0][u],dp[1][u]);
      dp[1][v]+=dp[0][u];
    }
    return;
  };
  int ans=0;
  for(int i=0;i<k;i++){
    if(used[i]) continue;
    dfs(i,-1);
    ans+=max(dp[0][i],dp[1][i]);
  }
  cout<<ans<<endl;
  return 0;
}

/*
  verified on 2019/05/29
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0377
*/

signed ARC045_D(){
  cin.tie(0);
  ios::sync_with_stdio(0);
    
  int n;
  cin>>n;
  vector<int> xs(2*n+1),ys(2*n+1);
  for(int i=0;i<2*n+1;i++) cin>>xs[i]>>ys[i];

  vector<vector<int> > R(2*n+2),C(2*n+2);
  for(int i=0;i<2*n+1;i++) R[xs[i]].emplace_back(i);
  for(int i=0;i<2*n+1;i++) C[ys[i]].emplace_back(i);

  UnionFind uf(2*n+1);
  for(auto &v:R)
    for(auto u:v) uf.unite(v[0],u);
  for(auto &v:C)
    for(auto u:v) uf.unite(v[0],u);

  vector<int> vs;
  for(int i=0;i<2*n+1;i++){
    if(uf.find(i)!=i) continue;
    if(uf.size(i)&1) vs.emplace_back(i);
  }
  assert(!vs.empty());
  
  if(vs.size()>1u){
    for(int i=0;i<2*n+1;i++) cout<<"NG\n";
    cout<<flush;
    return 0;    
  }
  
  LowLink G(2*n+1);
  auto add_edge=
    [&](auto &V)->void{
      for(auto &v:V){
        if(v.empty()) continue;
        if(!uf.same(vs[0],v[0])) continue;
        if(v.size()>0u) for(auto u:v) G.add_edge(v[0],u);
        if(v.size()>1u) for(auto u:v) G.add_edge(v[1],u);
      }
    };
  add_edge(R);
  add_edge(C);

  G.build();
  auto ap=G.ap; 
  
  vector<int> ans(2*n+1,0);
  for(int i=0;i<2*n+1;i++)
    if(uf.same(vs[0],i)) ans[i]=1;

  for(int v:ap){
    if(!uf.same(vs[0],v)) continue;
    for(int u:G.G[v]){
      if(G.par[u]!=v) continue;    
      if(~G.par[v]&&G.ord[v]>G.low[u]) continue;     
      if(G.num[u]&1) ans[v]=0;
    }
  }
  
  for(int i=0;i<2*n+1;i++) cout<<(ans[i]?"OK\n":"NG\n");
  cout<<flush;
  return 0;
}
/*
  verified on 2019/03/23
  https://atcoder.jp/contests/arc045/tasks/arc045_d
*/


signed ARC062_F(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  
  int n,m,k;
  cin>>n>>m>>k;

  using P = pair<int, int>;
  map<P, int> idx;
  
  LowLink G(n);
  for(int i=0;i<m;i++){
    int a,b;
    cin>>a>>b;
    a--;b--;
    G.add_edge(a,b);
    idx[P(a,b)]=idx[P(b,a)]=i;
  }

  G.build();
  
  UnionFind uf(m);
  for(auto vs:G.E)
    for(auto p:vs) uf.unite(idx[p],idx[vs[0]]);  

  vector<set<int>> cnt(m);  
  for(auto vs:G.E){
    for(auto p:vs){
      cnt[uf.find(idx[p])].emplace(p.first);     
      cnt[uf.find(idx[p])].emplace(p.second);
    }
  }
  
  using M = Mint<int>;
  using E = Enumeration<M>;
  E::init(1000);
  
  auto calc1=
    [&](int x)->M{     
      M res{0};
      
      for(int i=0;i<x;i++)
        res+=M(k).pow(__gcd(i,x));
      
      res*=E::invs[x];
      return res;
    };

  M ans{1};
  for(int i=0;i<m;i++){
    if(uf.find(i)!=i) continue;
    if(uf.size(i)< (int)cnt[i].size()) ans*=M(k).pow(uf.size(i));
    if(uf.size(i)==(int)cnt[i].size()) ans*=calc1(uf.size(i));
    if(uf.size(i)> (int)cnt[i].size()) ans*=E::H(k,uf.size(i));
  }  
  cout<<ans.v<<endl;
  return 0;
}
/*
  verified on 2019/05/29
  https://atcoder.jp/contests/arc062/tasks/arc062_d
*/


signed main(){
  //GRL_3_A();
  //GRL_3_B();
  AOJ_0377();
  //ARC045_D();  
  //ARC062_F();
  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 29544
final_rank: 12

code_snippet: #include<bits/stdc++.h>
using namespace std;
//BEGIN CUT HERE
struct LowLink{
  int n,pos;
  vector<int> ord,low,par,blg,num;
  vector<vector<int> > G,C,T;
  
  vector<int> ap;
  vector<pair<int, int> > bs;

  LowLink(int n):n(n),pos(0),ord(n,-1),low(n),
                 par(n,-1),blg(n,-1),num(n,1),G(n){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  bool is_bridge(int u,int v){
    if(ord[u]>ord[v]) swap(u,v);
    return ord[u]<low[v];
  }

  void dfs(int v){
    ord[v]=low[v]=pos++;
    for(int u:G[v]){
      if(u==par[v]) continue;
      if(~ord[u]){
        low[v]=min(low[v],ord[u]);
        continue;
      }
      par[u]=v;
      dfs(u);
      num[v]+=num[u];
      low[v]=min(low[v],low[u]);
      if(is_bridge(u,v)) bs.emplace_back(u,v);
    }
  }

  void fill_component(int v){
    C[blg[v]].emplace_back(v);
    for(int u:G[v]){
      if(~blg[u]||is_bridge(u,v)) continue;
      blg[u]=blg[v];
      fill_component(u);
    }
  }

  void add_component(int v,int &k){
    if(~blg[v]) return;
    blg[v]=k++;
    C.emplace_back();
    fill_component(v);
  }
  
  int build(){
    for(int i=0;i<n;i++)
      if(ord[i]<0) dfs(i);
    
    vector<int> cnt(n,0);
    for(int i=0;i<n;i++){
      int p=par[i];
      if(p<0) continue;
      if(par[p]<0) cnt[p]++;
      else if(ord[p]<=low[i]) ap.emplace_back(p);
    }
    
    for(int i=0;i<n;i++)
      if(cnt[i]>1) ap.emplace_back(i);

    sort(ap.begin(),ap.end());
    ap.erase(unique(ap.begin(),ap.end()),ap.end());

    int k=0;    
    for(int i=0;i<n;i++) add_component(i,k);

    T.assign(k,vector<int>());    
    for(auto e:bs){
      int u=blg[e.first],v=blg[e.second];
      T[u].emplace_back(v);
      T[v].emplace_back(u);
    }
    return k;
  }
};
//END CUT HERE

struct UnionFind{
  int n;
  vector<int> r,p;
  UnionFind(){}
  UnionFind(int sz):n(sz),r(sz,1),p(sz,0){iota(p.begin(),p.end(),0);}
  int find(int x){
    return (x==p[x]?x:p[x]=find(p[x]));
  }
  bool same(int x,int y){
    return find(x)==find(y);
  }
  void unite(int x,int y){
    x=find(x);y=find(y);
    if(x==y) return;
    if(r[x]<r[y]) swap(x,y);
    r[x]+=r[y];
    p[y]=x;
  }
  int size(int x){
    return r[find(x)];
  }
};

//INSERT ABOVE HERE
signed GRL_3_A(){
  int n,m;
  scanf("%d %d",&n,&m);
  LowLink G(n);
  for(int i=0;i<m;i++){
    int u,v;
    scanf("%d %d",&u,&v);
    G.add_edge(u,v);
  }
  G.build();
  auto ap=G.ap;
  sort(ap.begin(),ap.end());
  for(int v:ap) printf("%d\n",v);
  return 0;
}
/*
  verified on 2019/03/23
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_3_A&lang=jp
*/
signed GRL_3_B(){
  int n,m;
  scanf("%d %d",&n,&m);
  
  LowLink G(n);
  for(int i=0;i<m;i++){
    int u,v;
    scanf("%d %d",&u,&v);
    G.add_edge(u,v);
  }
  G.build();
  
  auto bs=G.bs;
  for(auto &e:bs)
    if(e.first>e.second) swap(e.first, e.second);
  
  sort(bs.begin(),bs.end());
  for(auto e:bs) printf("%d %d\n",e.first, e.second);
  
  return 0;
}
/*
  verified on 2019/03/23
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_3_B&lang=jp
*/

signed ARC045_D(){
  cin.tie(0);
  ios::sync_with_stdio(0);
    
  int n;
  cin>>n;
  vector<int> xs(2*n+1),ys(2*n+1);
  for(int i=0;i<2*n+1;i++) cin>>xs[i]>>ys[i];

  vector<vector<int> > R(2*n+2),C(2*n+2);
  for(int i=0;i<2*n+1;i++) R[xs[i]].emplace_back(i);
  for(int i=0;i<2*n+1;i++) C[ys[i]].emplace_back(i);

  UnionFind uf(2*n+1);
  for(auto &v:R)
    for(auto u:v) uf.unite(v[0],u);
  for(auto &v:C)
    for(auto u:v) uf.unite(v[0],u);

  vector<int> vs;
  for(int i=0;i<2*n+1;i++){
    if(uf.find(i)!=i) continue;
    if(uf.size(i)&1) vs.emplace_back(i);
  }
  assert(!vs.empty());
  
  if(vs.size()>1u){
    for(int i=0;i<2*n+1;i++) cout<<"NG\n";
    cout<<flush;
    return 0;    
  }
  
  LowLink G(2*n+1);
  auto add_edge=
    [&](auto &V)->void{
      for(auto &v:V){
        if(v.empty()) continue;
        if(!uf.same(vs[0],v[0])) continue;
        if(v.size()>0u) for(auto u:v) G.add_edge(v[0],u);
        if(v.size()>1u) for(auto u:v) G.add_edge(v[1],u);
      }
    };
  add_edge(R);
  add_edge(C);

  G.build();
  auto ap=G.ap; 
  
  vector<int> ans(2*n+1,0);
  for(int i=0;i<2*n+1;i++)
    if(uf.same(vs[0],i)) ans[i]=1;

  for(int v:ap){
    if(!uf.same(vs[0],v)) continue;
    for(int u:G.G[v]){
      if(G.par[u]!=v) continue;    
      if(~G.par[v]&&G.ord[v]>G.low[u]) continue;     
      if(G.num[u]&1) ans[v]=0;
    }
  }
  
  for(int i=0;i<2*n+1;i++) cout<<(ans[i]?"OK\n":"NG\n");
  cout<<flush;
  return 0;
}
/*
  verified on 2019/03/23
  https://atcoder.jp/contests/arc045/tasks/arc045_d
*/

signed AOJ_0377(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  
  int n,m;
  cin>>n>>m;
  LowLink bg(n);
  for(int i=0;i<m;i++){
    int a,b;
    cin>>a>>b;
    bg.add_edge(a,b);
  }
  int k=bg.build();
  auto& G=bg.T;
  
  vector<int> c(k);
  for(int i=0;i<k;i++) c[i]=bg.C[i].size();
  vector<vector<int> > dp(2,vector<int>(k,0));
  vector<int> used(k,0);
  function<void(int,int)> dfs=[&](int v,int p){
    if(used[v]) return;
    used[v]=1;
    dp[0][v]=0;
    dp[1][v]=c[v];
    for(int u:G[v]){
      if(u==p) continue;
      dfs(u,v);
      dp[0][v]+=max(dp[0][u],dp[1][u]);
      dp[1][v]+=dp[0][u];
    }
    return;
  };
  int ans=0;
  for(int i=0;i<k;i++){
    if(used[i]) continue;
    dfs(i,-1);
    ans+=max(dp[0][i],dp[1][i]);
  }
  cout<<ans<<endl;
  return 0;
}

/*
  verified on 2019/05/29
  http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0377
*/

signed main(){
  //GRL_3_A();
  //GRL_3_B();
  //ARC045_D();  
  AOJ_0377();  
  return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 23988
final_rank: 10

code_snippet: #include <iostream>
#include <algorithm>
#include <vector>
#include <stdlib.h>
#include <stack>
#include <set>
#include <map>
#include <functional>
#include <array>

using namespace std;
struct LowLink {
	set<pair<int, int>> bridge;
	vector<int> articulation, ord, low;
	vector<bool> used;
	vector<vector<int>> g;
	int n, k = 0;
	LowLink(const vector<vector<int>> &g) : g(g) {
		n = g.size();
		ord.resize(n, 0);
		low.resize(n, 0);
		used.resize(n, false);
	}
	void dfs(int u, int prev) {

		used[u] = true;
		ord[u] = k++;
		low[u] = ord[u];
		bool is_articulation = false;
		int cnt = 0;
		for (auto v : g[u]) if (v != prev) {
			if (!used[v]) {
				cnt++;
				dfs(v, u);
				low[u] = min(low[u], low[v]);
				if (low[v] > ord[u]) {
					bridge.emplace(min(u, v), max(u, v));
				}
				if (prev != -1 && low[v] >= ord[u]) {
					is_articulation = true;
				}
			}
			else {
				low[u] = min(low[u], ord[v]);
			}
		}
		if (prev == -1 && cnt > 1) is_articulation = true;
		if (is_articulation) articulation.push_back(u);
	}
};
struct TwoEdgeConnectedComponent {
	int n;
	vector<vector<int>> g, tree;
	vector<int> cmp;
	TwoEdgeConnectedComponent(const vector<vector<int>> &g) : g(g) {
		n = (int)g.size();
		cmp.assign(n, -1);
	}
	void build() {
		LowLink lnk(g);
		for (int i = 0; n > i; i++) {
			if(lnk.used[i] == false)
				lnk.dfs(i, -1);
		}
		int k = 0;
		function<void(int, int)> dfs = [&](int u, int prev) {
			cmp[u] = k;
			for (auto v : g[u]) if (cmp[v] == -1 && lnk.bridge.count({ min(u, v), max(u, v) }) == 0) {
				dfs(v, u);
			}
		};
		for (int i = 0; i < n; i++) if (cmp[i] == -1) {
			dfs(i, -1);
			k++;
		}
		tree.resize(k);
		for (auto e : lnk.bridge) {
			tree[cmp[e.first]].push_back(cmp[e.second]);
			tree[cmp[e.second]].push_back(cmp[e.first]);
		}
	}
};

int main() {

	int n, m;
	cin >> n >> m;
	vector<vector<int>> g(n);

	for (int i = 0; m > i; i++) {
		int s, t;
		cin >> s >> t;
		g[s].push_back(t);
		g[t].push_back(s);
	}

	TwoEdgeConnectedComponent tecc(g);
	tecc.build();
	
	vector<int> sz(tecc.tree.size());
	vector<array<int, 2>> dp(tecc.tree.size());

	for (int i = 0; n > i; i++) {
		sz[tecc.cmp[i]]++;
	}

	function<void(int, int)> dfs = [&](int cur, int par){
		dp[cur][1] = sz[cur];
		for (auto itr : tecc.tree[cur]) {
			if (itr == par) continue;
			dfs(itr, cur);
			dp[cur][0] += max(dp[itr][0], dp[itr][1]);
			dp[cur][1] += dp[itr][0];
		}
	};

	int ans = 0;

	for (int i = 0; tecc.tree.size() > i; i++) {
		if (dp[i][1] == 0) {
			dfs(i, -1);
			ans += max(dp[i][0],dp[i][1]);
		}
	}

	cout << ans << endl;

	return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 31068
final_rank: 15