jiahuimbzuai/CoQuIR huggingface dataset:
//  [typescript]
import * as fs from "fs";

// inputで受け取り配列化する
const input = fs.readFileSync("/dev/stdin", "utf8").split("\n");
const N = Number(input[0]);
const h = input[1].split(" ").map(Number);

const dp = Array(N).fill(Infinity);

dp[0] = 0;
dp[1] = Math.abs(h[1] - h[0]);

for (let index = 2; index < N; index++) {
  const oneJump = Math.abs(h[index] - h[index - 1]) + dp[index - 1];
  const twoJump = Math.abs(h[index] - h[index - 2]) + dp[index - 2];
  dp[index] = Math.min(oneJump, twoJump);
}

console.log(dp[dp.length - 1]);
//  [typescript]
// https://atcoder.jp/contests/dp/tasks/dp_a

import * as fs from "fs";

const split_number = (str: string): number[] => {
  return str.split(" ").map((v: string) => +v);
};

function main(input: string) {
  const lines = input.split("\n");
  const [n] = split_number(lines[0]);

  const h: number[] = split_number(lines[1]);
  let dp: number[] = new Array(n).fill(Infinity);
  dp[0] = 0;

  let result: number = 0;

  for (let i = 0; i < n; i++) {
    if (i >= 2) {
      dp[i] = Math.min(dp[i], dp[i - 2] + Math.abs(h[i] - h[i - 2]));
    }
    if (i >= 1) {
      dp[i] = Math.min(dp[i], dp[i - 1] + Math.abs(h[i] - h[i - 1]));
    }
  }

  console.log(dp[n - 1]);
}

main(fs.readFileSync("/dev/stdin", "utf8"));
//  [typescript]
function main(input: string) {
  const [N, hs] = input.split("\n").map((v,i) => i % 2 === 0 ? parseInt(v) : v.split(" ").map(vv=>parseInt(vv)));
  const arr = new Array(N);
  arr.fill(Infinity);
  arr[0] = 0 // 初期値
  for (let i = 1; i < N; i++) {
    // 2個前から
    if (i - 2 >= 0) {
      arr[i] = Math.min(arr[i], arr[i-2] + Math.abs(hs[i] - hs[i-2]));
    }
    // 1個前から
    if (i - 1 >= 0) {
      arr[i] = Math.min(arr[i], arr[i-1] + Math.abs(hs[i] - hs[i-1]));
    }
  }
  console.log(arr[N-1]);
}

main(
  require("fs")
    .readFileSync("/dev/stdin", "utf8")
    .trim()
);
//  [typescript]
const lines: string[] = [];
const reader = require("readline").createInterface({
  input: process.stdin,
  output: process.stdout,
});
reader.on("line", function (line: string) {
  lines.push(line);
});

let dp: any;
let inputSize;

//数字の配列
let input: any;

reader.on("close", function () {
  inputSize = Number(lines[0]);

  //数字の配列
  input = lines[1].split(" ").map(Number);
  dp = [inputSize];
  for (let i = 0; i < inputSize; i++)
    dp[i] = {
      value: Infinity,
    };

  dp[0] = { value: 0 };

  // for (let i = 1; i < dp.length; i++) {
  //   chmin(dp[i], { value: dp[i - 1].value + abs(input[i] - input[i - 1]) });
  //   if (i > 1)
  //     chmin(dp[i], { value: dp[i - 2].value + abs(input[i] - input[i - 2]) });
  // }

  console.log(rec(Number(inputSize) - 1).value);
  // console.log(dp);
});

function rec(i: number): any {
  if (dp[i] < Infinity) return dp[i];

  if (i === 0) return { value: 0 };

  let res = { value: Infinity };

  if (i > 0)
    chmin(res, { value: rec(i - 1).value + abs(input[i] - input[i - 1]) });
  if (i > 1)
    chmin(res, { value: rec(i - 2).value + abs(input[i] - input[i - 2]) });

  dp[i] = res;
  return dp[i];
}

function chmin(a: any, b: any): boolean {
  if (a.value > b.value) {
    a.value = b.value;
    return true;
  }
  return false;
}

function chmax(a: any, b: any): boolean {
  if (a.value < b.value) {
    a = b;
    return true;
  }
  return false;
}

function abs(val: number) {
  return val < 0 ? -val : val;
}
//  [typescript]
const lines: string[] = [];
const reader = require("readline").createInterface({
  input: process.stdin,
  output: process.stdout,
});
reader.on("line", function (line: string) {
  lines.push(line);
});

let dp: any;
let inputSize;

//数字の配列
let input: any;

reader.on("close", function () {
  inputSize = Number(lines[0]);

  //数字の配列
  input = lines[1].split(" ").map(Number);
  dp = [inputSize];
  for (let i = 0; i < inputSize; i++)
    dp[i] = {
      value: Infinity,
    };

  dp[0] = { value: 0 };

  // for (let i = 1; i < dp.length; i++) {
  //   chmin(dp[i], { value: dp[i - 1].value + abs(input[i] - input[i - 1]) });
  //   if (i > 1)
  //     chmin(dp[i], { value: dp[i - 2].value + abs(input[i] - input[i - 2]) });
  // }

  console.log(rec(Number(inputSize) - 1).value);
  console.log(dp);
});

function rec(i: number): any {
  if (dp[i] < Infinity) return dp[i];

  if (i === 0) return { value: 0 };

  let res = { value: Infinity };

  if (i > 0)
    chmin(res, { value: rec(i - 1).value + abs(input[i] - input[i - 1]) });
  if (i > 1)
    chmin(res, { value: rec(i - 2).value + abs(input[i] - input[i - 2]) });

  dp[i] = res;
  return dp[i];
}

function chmin(a: any, b: any): void {
  if (a.value > b.value) {
    a.value = b.value;
    // return true;
  }
  // return false;
}

function chmax(a: any, b: any): boolean {
  if (a.value < b.value) {
    a = b;
    return true;
  }
  return false;
}

function abs(value: number) {
  return Math.abs(value);
}
//  [typescript]
const lines: string[] = [];
const reader = require("readline").createInterface({
  input: process.stdin,
  output: process.stdout,
});
reader.on("line", function (line: string) {
  lines.push(line);
});

let dp: any;
let inputSize;

//数字の配列
let input: any;

reader.on("close", function () {
  inputSize = Number(lines[0]);

  //数字の配列
  input = lines[1].split(" ").map(Number);
  dp = [inputSize];
  for (let i = 0; i < inputSize; i++)
    dp[i] = {
      value: Infinity,
    };

  dp[0] = { value: 0 };

  // for (let i = 1; i < dp.length; i++) {
  //   chmin(dp[i], { value: dp[i - 1].value + abs(input[i] - input[i - 1]) });
  //   if (i > 1)
  //     chmin(dp[i], { value: dp[i - 2].value + abs(input[i] - input[i - 2]) });
  // }

  console.log(rec(Number(inputSize) - 1).value);
  // console.log(dp);
});

function rec(i: number): any {
  if (dp[i] < Infinity) return dp[i];

  if (i === 0) return { value: 0 };

  let res = { value: Infinity };

  if (i > 0)
    chmin(res, { value: rec(i - 1).value + abs(input[i] - input[i - 1]) });
  if (i > 1)
    chmin(res, { value: rec(i - 2).value + abs(input[i] - input[i - 2]) });

  dp[i] = res;
  return dp[i];
}

function chmin(a: any, b: any): boolean {
  if (a.value > b.value) {
    a.value = b.value;
    return true;
  }
  return false;
}

function chmax(a: any, b: any): boolean {
  if (a.value < b.value) {
    a = b;
    return true;
  }
  return false;
}

function abs(value: number) {
  return Math.abs(value);
}
//  [python]
import sys
if sys.argv[-1] == 'ONLINE_JUDGE':
    import os, zlib, base64
    open('solve.pyx', 'wb').write(zlib.decompress(base64.b85decode("c${TYO>cuR480@qAH2g<SksD5J4|Tok8~W85Fi=^lxC{7Uq74hU0=X{&(AMTO53&2Xd%xxXSJz7>bCE!gI2XS<-(vOg8X%LXU;vhylGT3lX}ZdrAE@IQs{2RE9GR(EkmL<t_%ZNs1oq^`kGMW(1(Ga6!i>F7X}`H7r5y^)s+#F<9Kdtv{BTL6HF9?=_=i%VE`DDGzbO~GDv*+Uh77|Wh7Au1V>|0yp(l`$OpW=ry#82-wQ%&5*=L<I3nkS91mLMeyjnxoC_Mo3uVbQ@U1`8@2@<^5lK3Aat{slZ0e;f-VC71YKCFZGT@9(su?&&4({63n|X#@)0TYNZqu@}piynS!l;c`8{%8;w6tA`FP1qj<+5Xskk~=E1`badh}FFHdOq<Z@*POwP?JBF$%S|<lLNOc5Aw%s(BC5>_v-Un{8mi7T;8d_YO*KO;Xw>(82E=B9iEFXbHIzhll}vB`qr2")))
    os.system('cythonize -i -3 -b solve.pyx')
import solve
//  [python]
import sys
if sys.argv[-1] == 'ONLINE_JUDGE':
    import os, zlib, base64
    open('solve.pyx', 'wb').write(zlib.decompress(base64.b85decode("c${TY%Wi`(5WFMt58Fc(Xq*VD9x7D&BPj>l7_bTkIj*Ai>${5yulNExGoBr<UD>{aRttH)I;%|$Qg=gd9dxR@Di;P73FNP9dUGDQ<!!6lSu|K~YBh-_ms0mLUn?gYZW#)-aa9<|QdNMzm)C?=0Ye!0PSL>Nlrr!HyueleslJL(9LLK>v^G%;rmuCIg#qB2DZxNO4vB|vjcygBlZci;a!M4%3#=<-KH%*=17Q{aUKnzd7$r^Mh?)~>JZY8tu?FNSSF3obEX4)B&4>QOg%{W&$?iM3r$#)#@1-i<G$3Tv!!YO=a7HK93>>2bH|?5DKSQZ$O1|v2Wz}2I=r-M5)Wxd_@vZhgv>n8k$Q*}~?$i?{b`*|*!&44o)o(qXPyC2tN78cW$sb`#As%5$;I{B+f6Pb!JtGS5K99vu#l*|yora61crqIw#8`%bf6>w5x%@H*ya+t$KlVq{`2")))
    os.system('cythonize -i -3 -b solve.pyx')
import solve
//  [python]
n, m = map(int, input().split())
lis = []
ans = 0
for _ in range(m):
  a, b = map(int, input().split())
  if len(lis) > 0:
    c = 0
    for i in range(len(lis)):
      if a in lis[i] or b in lis[i]:
        lis[i].append(a)
        lis[i].append(b)
        c += 1
        break
    if c == 0:
      lis.append([a, b])
  else:
    lis.append([a, b])

for x in lis:
  ans = max(ans, len(set(x)))
            
print(ans)
//  [python]
from collections import Counter

n, m = map(int, input().split())
if m == 0:
  print("0")
else:
  ab = [map(int, input().split()) for _ in range(m)]
  a, b = [list(i) for i in zip(*ab)]

  a.extend(b)
  c = Counter(a)
  most = c.most_common(1)[0][0]

  temp = []
  for i in range(m):
    if a[i] == most or b[i] == most:
      if a[i] == b[i]:
        continue
      temp.append(a[i])
      temp.append(b[i])
  temp = list(set(temp))
  print(len(temp))
//  [python]
from collections import Counter

n, m = map(int, input().split())
ab = [map(int, input().split()) for _ in range(m)]
a, b = [list(i) for i in zip(*ab)]

a.extend(b)
c = Counter(a)
most = c.most_common(1)[0][0]

temp = []
for i in range(m):
  if a[i] == most or b[i] == most:
    if a[i] == b[i]:
      continue
    temp.append(a[i])
    temp.append(b[i])
temp = list(set(temp))
print(len(temp))
//  [java]
import java.util.Scanner;

public class Main {

	static int MOD = 1000000007;

	public static void main(String[] args) {
		exec_1_1();

	}

	public static void exec_1_1() {

		try(var sc = new Scanner(System.in)) {

			int N = sc.nextInt();

			int M = sc.nextInt();

			int[] f = new int[N];


			for(int i=0; i<N; i++) f[i]=-1;

			for(int i=0; i<M; i++) {
				int a = sc.nextInt()-1;
				int b = sc.nextInt()-1;


				int rIdx = rootIdx(f, a);
				int rdxB = rootIdx(f, b);
				if(f[rIdx]>f[rdxB]) {
					int swap = rIdx;
					rdxB = rIdx;
					rIdx = swap;
				}
				if(rIdx==rdxB) continue ;

				f[rIdx] += f[rdxB];
				f[rdxB] = rIdx;
			}

			int min = 0;

			for(int i=0; i<N; i++) min = Math.min(min, f[i]);

			System.out.println(min*-1);
		}
	}


	public static int rootIdx(int[] f, int x) {

		if(f[x]<0)return x;

		return f[x] = rootIdx(f, f[x]);

	}
}
//  [java]
import java.util.Scanner;

public class Main {

	static int MOD = 1000000007;

	public static void main(String[] args) {
		exec_1_1();

	}

	public static void exec_1_1() {

		try(var sc = new Scanner(System.in)) {

			int N = sc.nextInt();

			int M = sc.nextInt();

			int[] f = new int[N];


			for(int i=0; i<N; i++) f[i]=-1;

			for(int i=0; i<M; i++) {
				int a = sc.nextInt()-1;
				int b = sc.nextInt()-1;

				if(f[a]>-1&&f[b]<0) {
					int swap = a;
					b = a;
					a = swap;
				}

				int rIdx = rootIdx(f, a);
				int rdxB = rootIdx(f, b);
				if(rIdx==rdxB) continue ;

				f[rIdx] += f[rdxB];
				f[rdxB] = rIdx;
			}

			int min = 0;

			for(int i=0; i<N; i++) min = Math.min(min, f[i]);

			System.out.println(min*-1);
		}
	}


	public static int rootIdx(int[] f, int x) {

		if(f[x]<0)return x;

		return rootIdx(f, f[x]);

	}
}
//  [java]
import java.util.Scanner;

public class Main {

	static int MOD = 1000000007;

	public static void main(String[] args) {
		exec_1_1();

	}

	public static void exec_1_1() {

		try(var sc = new Scanner(System.in)) {

			int N = sc.nextInt();

			int M = sc.nextInt();

			int[] f = new int[N];


			for(int i=0; i<N; i++) f[i]=-1;

			for(int i=0; i<M; i++) {
				int a = sc.nextInt()-1;
				int b = sc.nextInt()-1;

				if(f[a]>-1&&f[b]<0) {
					int swap = a;
					b = a;
					a = swap;
				}

				int rIdx = rootIdx(f, a);
				if(rIdx==rootIdx(f, b)) continue ;

				f[rIdx] += rootVal(f, b);
				f[b] = rIdx;
			}

			int min = 0;

			for(int i=0; i<N; i++) min = Math.min(min, f[i]);

			System.out.println(min*-1);
		}
	}


	public static int rootVal(int[] f, int x) {

		if(f[x]<0)return f[x];

		return rootVal(f, f[x]);

	}

	public static int rootIdx(int[] f, int x) {

		if(f[x]<0)return x;

		return rootIdx(f, f[x]);

	}
}
//  [cpp]
#pragma GCC optimize ("O2")
#pragma GCC target ("avx2")
//#include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;
typedef long long ll;
#define rep(i, n) for(int i = 0; i < (n); i++)
#define rep1(i, n) for(int i = 1; i <= (n); i++)
#define co(x) cout << (x) << "\n"
#define cosp(x) cout << (x) << " "
#define ce(x) cerr << (x) << "\n"
#define cesp(x) cerr << (x) << " "
#define pb push_back
#define mp make_pair
#define chmin(x, y) x = min(x, y)
#define chmax(x, y) x = max(x, y)
#define Would
#define you
#define please

const int CM = 1 << 17, CL = 12;
char cn[CM + CL], * ci = cn + CM + CL, * owa = cn + CM, ct;
const ll ma0 = 1157442765409226768;
const ll ma1 = 1085102592571150095;
const ll ma2 = 71777214294589695;
const ll ma3 = 281470681808895;
const ll ma4 = 4294967295;
inline int getint() {
	if (ci - owa > 0) {
		memcpy(cn, owa, CL);
		ci -= CM;
		fread(cn + CL, 1, CM, stdin);
	}
	ll tmp = *(ll*)ci;
	int dig = 68 - __builtin_ctzll((tmp & ma0) ^ ma0);
	tmp = tmp << dig & ma1;
	tmp = tmp * 10 + (tmp >> 8) & ma2;
	tmp = tmp * 100 + (tmp >> 16) & ma3;
	tmp = tmp * 10000 + (tmp >> 32) & ma4;
	ci += 72 - dig >> 3;
	return tmp;
}
const int SZ = 200000;
class UF {
public:
	int P[SZ + 1], saidai;
	UF() : P(), saidai() {
		saidai = -1;
		rep1(i, SZ) P[i] = -1;
	}
	int find(int A) {
		if (P[A] < 0) return A;
		return P[A] = find(P[A]);
	}
	bool unite(int A, int B) {
		int a = find(A);
		int b = find(B);
		if (a == b) return false;
		if (P[a] > P[b]) swap(a, b);
		P[a] += P[b];
		if (P[a] < saidai) saidai = P[a];
		P[b] = a;
		return true;
	}
} uf;

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

	int N = getint(), M = getint();

	rep(i, M) {
		uf.unite(getint(), getint());
	}

	printf("%d\n", -uf.saidai);


	Would you please return 0;
}
//  [cpp]
#include<bits/stdc++.h>
#define rep(i,n) for (ll i=0; i<(n); i++)
using namespace std;
using ll = long long;
using ld = long double;
using vl = vector<ll>;

struct UnionFind {
  vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2

    UnionFind(int N) : par(N) { //最初は全てが根であるとして初期化
      rep(I,N) par[i] = i;
    }

    ll root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
      if (par[x] == x) return x;
      return par[x] = root(par[x]);
    }

    void unite(int x, int y) { // xとyの木を併合
      ll rx = root(x); //xの根をrx
      ll ry = root(y); //yの根をry
      if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
      par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
   }
  
   bool same (ll x, ll y) { // 2つのデータx, yが属する木が同じならtrueを返す
     ll rx = root(x);
     ll ry = root(y);
     return rx == ry;
   }
  
   ll size (ll x) {
     return -r[root(x)];
   }
};

int main() {
  ll n, m;
  cin >> n >> m;
  
  UnionFind uf(n);
  
  rep(i,m) {
    ll a, b;
    cin >> a >> b;
    a--; b--;
    uf.unite(a,b);
  }
  ll ans = 0;
  rep(i,n) ans = max(uf.size(i), ans);
  cout << ans << endl;
}
//  [cpp]
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define P pair<ll,ll>

class UnionFind {
    vector<int> data;
    ll num;
public:
    UnionFind(int size) : data(size, -1), num(size) { }
    bool unite(int x, int y) {//xとyの集合を統合する
        x = root(x); y = root(y);
        if (x != y) {
            if (data[y] < data[x]) swap(x, y);
            data[x] += data[y]; data[y] = x;
        }
        num -= (x != y);
        return x != y;
    }
    bool findSet(int x, int y) {//xとyが同じ集合か返す
        return root(x) == root(y);
    }
    int root(int x) {//xのルートを返す
        return data[x] < 0 ? x : data[x] = root(data[x]);
    }
    ll size(int x) {//xの集合のサイズを返す
        return -data[root(x)];
    }
    ll numSet() {//集合の数を返す
        return num;
    }
};
 int main(){
ll n,m;
   cin>>n>>m;
   UnionFind uf(n);
   rep(i,m){
     ll a,b;
     cin>>a>>b;
     a--;b--;
   uf.unite(a,b));
   }
   ll ans=0;
   rep(i,n){
     ans=max(ans,uf.size(i));
   }
   cout<<ans<<endl;
}
//  [cpp]
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define P pair<ll,ll>

class UnionFind {
    vector<int> data;
    ll num;
public:
    UnionFind(int size) : data(size, -1), num(size) { }
    bool unite(int x, int y) {//xとyの集合を統合する
        x = root(x); y = root(y);
        if (x != y) {
            if (data[y] < data[x]) swap(x, y);
            data[x] += data[y]; data[y] = x;
        }
        num -= (x != y);
        return x != y;
    }
    bool findSet(int x, int y) {//xとyが同じ集合か返す
        return root(x) == root(y);
    }
    int root(int x) {//xのルートを返す
        return data[x] < 0 ? x : data[x] = root(data[x]);
    }
    ll size(int x) {//xの集合のサイズを返す
        return -data[root(x)];
    }
    ll numSet() {//集合の数を返す
        return num;
    }
};
 int main(){
ll n,m;
   cin>>n>>m;
   UnionFind uf(n);
   rep(i,m){
     ll a,b;
     cin>>a>>b;
     a--;b--;
   uf(.unite(a,b));
   }
   ll ans=0;
   rep(i,n){
     ans=max(ans,uf.size(i));
   }
   cout<<ans<<endl;
}
//  [c]
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
inline int max(const int a, const int b){return a>b?a:b;}
//fast(?) Input
#define buf_sz 1<<24
char buf[buf_sz];
unsigned int nextint(){
	static int id = 0;
	if(id == 0)read(0, buf, buf_sz);
	unsigned int res = 0;
	while(id<buf_sz && buf[id]<'0' || '9'<buf[id])id++;
	while(id<buf_sz && '0'<=buf[id] && buf[id]<='9'){
		res *= 10;
		res += buf[id++] - '0';
	}if(id>=buf_sz)exit(1);
	return res;
}
#undef buf_sz

int d[] = {[0 ... 1<<18] -1};
int find(int x){
	if(d[x] < 0) return x;
	return d[x] = find(d[x]);
}
bool unite(int x, int y){
	x = find(x); y = find(y);
	if(x == y)return false;
	if(d[x] > d[y]){
		int tmp = x;
		x = y;
		y = tmp;
	}
	d[x] += d[y];
	d[y] = x;
	return true;
}
bool same(int x, int y){return find(x) == find(y);}
int size(int x){return -d[find(x)];}

int ans;
int main(){
	int N = nextint(), M = nextint();
	while(M--)unite(nextint(), nextint());
	for(int i=1; i<=N; i++)ans = max(ans, size(i));
	printf("%d\n", ans);
	return 0;
}
//  [c]
#include <ctype.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
#ifdef __cplusplus
#include <bits/stdc++.h>
#endif
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")

//char rbuf[]; int rbufl;
//#define getchar() rbuf[rbufl++]
#define getchar getchar_unlocked
#define putchar putchar_unlocked
int32_t nextint(void){ char c=getchar(); while(c!='-'&&(c<'0'||'9'<c)) c=getchar(); bool s=false; if(c=='-'){s=true;c=getchar();} uint32_t x=0; while('0'<=c && c<='9'){ x=x*10+c-'0'; c=getchar(); } return s?-x:x; }
int64_t nextlong(void){ char c=getchar(); while(c!='-'&&(c<'0'||'9'<c)) c=getchar(); int s=0; if(c=='-'){s=1;c=getchar();} uint64_t x=0; while('0'<=c && c<='9'){ x=x*10+c-'0'; c=getchar(); } return s?-x:x; }
uint32_t nextstr(char *s){ char c=getchar(); while(c==' '||c=='\n') c=getchar(); uint32_t len=0; while(c!=' '&&c!='\n'){ *s++=c; len++; c=getchar(); } *s='\0'; return len; }
void printint(int32_t x){ if(x<0){x=-x; putchar('-');}else if(x==0){putchar('0');} int d=0; char s[10]; while(x){ s[d]='0'+x%10; x/=10; d++; } for (int i=d-1; i>=0; i--) putchar(s[i]); putchar('\n'); }
void rsorta_d32(void *base, const int count, const int size, const int index){
	typedef int32_t rsort_t;
	rsort_t (*a)[size] = (rsort_t(*)[size])base;
	rsort_t (*b)[size] = (rsort_t(*)[size])malloc(count*size*sizeof(rsort_t));
	int c[0x100];
	for(int k=0; k<4; k++){
		memset(c, 0, sizeof(c)); for(int i=0; i<count; i++){ c[(a[i][index]>>(k<<3))&0xFF]++; } for(int i=1; i<0x100; i++) c[i]+=c[i-1]; for(int i=count-1; i>=0; i--){ int to=--c[(a[i][index]>>(k<<3))&0xFF]; for(int j=0; j<size; j++){ b[to][j]=a[i][j]; } }{rsort_t(*t)[size]=a; a=b; b=t;}
	}
	free(b);
}

int prev[200001];
int rank[200001];
int size[200001];

void init(int n){
	for(int i=1; i<=n; i++){ prev[i]=i; rank[i]=1; size[i]=1; }
}
int root(int x){
	return prev[x]==x?x:(prev[x]=root(prev[x]));
}
void join(int x, int y){
	x=root(x), y=root(y);
	if(x==y) return;
	if(rank[x]<rank[y]){
		prev[x]=y;
		size[y]+=size[x];
	}else if(rank[x]>rank[y]){
		prev[y]=x;
		size[x]+=size[y];
	}else{
		prev[x]=y;
		rank[y]++;
		size[y]+=size[x];
	}
}

int main(void){
	int n=nextint();
	int m=nextint();
	init(n);
	for(int i=0; i<m; i++){
		int a=nextint();
		int b=nextint();
		join(a, b);
	}
	int ans=0;
	for(int i=1; i<=n; i++){
		int now = size[root(i)];
		if(now>ans) ans=now;
	}
	printf("%d\n", ans);
}
//  [c]
#include<stdio.h>
#include<stdlib.h>
int *a, *MAXGROUP;
int findRoot(int x){
  if (a[x]<0) return x;
  else return findRoot(a[x]);
}
void unite( int c, int b, int *p ){
  int q=findRoot(c);
  int w=findRoot(b);
  if (w!=q){
    a[q]+=a[w];
    a[w]=q;
    if (*p>a[q]) *p=a[q];
  }
}
int main(){
  int m,n,k1,k2,max=-1;
  MAXGROUP=&max;
  scanf("%d%d",&n,&m);
  int i;
  a=(int*)malloc(n*sizeof(int));
  for (i=0;i<n;i++) a[i]=-1;
  for (i=0;i<m;i++){
    scanf("%d%d",&k1,&k2);
    k1--;k2--;
    unite(k1,k2,MAXGROUP);
  }
  free(a);
  printf("%d\n",-max);
}
//  [c]
#include<stdio.h>
#include<stdlib.h>
int *a, *MAXGROUP;
int findRoot(int x){
  if (a[x]<0) return x;
  else return findRoot(a[x]);
}
void unite( int c, int b, int *p ){
  int q=findRoot(c);
  int w=findRoot(b);
  if (w!=q){
    a[q]+=a[w];
    a[w]=q;
    if (*p>a[q]) *p=a[q];
  }
}
int main(){
  int m,n,k1,k2,max=-1;
  MAXGROUP=&max;
  scanf("%d%d",&n,&m);
  int i;
  a=(int*)malloc(n*sizeof(int));
  for (i=0;i<n;i++) a[i]=-1;
  for (i=0;i<m;i++){
    scanf("%d%d",&k1,&k2);
    k1--;k2--;
    unite(k1,k2,MAXGROUP);
  }
  free(a);
  printf("%d\n",max);
}
//  [c]
#include<stdio.h>
#include<stdlib.h>
int *a, *MAXGROUP;
int findRoot(int x){
  if (a[x]<0) return x;
  else return findRoot(a[x]);
}
void unite( int c, int b, int *p ){
  int q=findRoot(c);
  int w=findRoot(b);
  if (w!=q){
    a[q]+=a[w];
    a[w]=q;
    if (*p>a[q]) *p=a[q];
  }
}
int main(){
  int m,n,k1,k2,max=-1;
  MAXGROUP=&max;
  scanf(%d%d,&n,&m);
  int i;
  a=(int*)malloc(n*sizeof(int));
  for (i=0;i<n;i++) a[i]=-1;
  for (i=0;i<m;i++){
    scanf("%d%d",&k1,&k2);
    k1--;k2--;
    unite(k1,k2,MAXGROUP);
  }
  free(a);
  printf("%d\n",max);
}
//  [javascript]
let input = require('fs').readFileSync('/dev/stdin', 'utf8')
// let input = require('fs').readFileSync('./sample_d.txt', 'utf8')
.split(/\n| /)
.slice(0 ,-1)
.map(item => parseInt(item))

const [N, M, ..._pair] = input

let r = new Array(N).fill(-1)

const root = x => {
    if (r[x] < 0) return x
    return r[x] = root(r[x])
}

const unite = (x, y) => {
    x = root(x)
    y = root(y)
    if (x == y) return false
    if (r[x] > r[y]) [x, y] = [y, x]
    r[x] += r[y]
    r[y] = x
    return true
}

const size = x => {
    return -r[root(x)]
}


for (let i=0; i<_pair.length; i+=2){
    unite(_pair[i]-1, _pair[i+1]-1)
}
 
//最大の友達集合を求める
let ans = 0
for ( let i=0; i<N; i++){
    ans = Math.max(ans, size(i));
}

console.log(ans)

// const [N, M, ..._pair] = input
// const pair = []
// for(let i=0; i<N; i++){
//     pair.push(new Array(N-i).fill(true))
// }

// for(let i=0; i<_pair.length; i+=2){
//     const a = [_pair[i], _pair[i+1]].sort()
//     pair[a[0]-1][a[1]-a[0]] = false
// }


// const member = [ new Set() ]

// pair[0].forEach( (item, index) => {
//     if(item) member[0].add(index+1)
//     else{
//         member.push(new Set())
//         member[member.length-1].add(index+1)
//     }
// } )

// for( let i=1; i<N; i++){
//     for( let j=1; j<pair[i].length; j++){
//         if(!pair[i][j]){
//             member.forEach( (sample, index) => {
//                 if( sample.has(i+1) && sample.has(i+j+1) ){
//                     sample.delete(i+j)
//                     if(member.length - 1 <= index) member.push(new Set())
//                     member[index+1].add(i+j)
//                 }
//             })
//         }
//     }
// }

// console.log(member.length)
//  [javascript]
class UnionFind {
    constructor(N){
        this.par = new Array(N).fill(-1)
    }

    root(x) {
        if (this.par[x] < 0) return x;
        return this.par[x] = this.root(this.par[x]);
    }

    unite(x, y) {
        let rx = this.root(x);
        let ry = this.root(y);
        if (rx == ry) return;
        if(this.par[rx] > this.par[ry]) [rx, ry] = [ry, rx]
        this.par[rx] += this.par[ry]
        this.par[ry] = rx
    }

    isSame(x, y) {
        let rx = this.root(x);
        let ry = this.root(y);
        return rx == ry;
    }
    
    size(x) {
        return -this.par[this.root(x)];
    }
};

function main(arg) {
    
    arg = arg.split("\n")
    let [N,M] = arg[0].split(" ").map(Number)
    let A = arg.slice(1).map(x=>Number(x.split(" ")[0]))
    let B = arg.slice(1).map(x=>Number(x.split(" ")[1]))
    

    let tree = new UnionFind(N)
    for(let i=0; i<M; i++) {
        tree.unite(A[i]-1,B[i]-1)
    }

    let ans=0
    for(let i=0; i<N; i++) {
        ans = Math.max(ans, tree.size(i))
    }
    console.log(ans)
}

main(require('fs').readFileSync('/dev/stdin', 'utf8'))
//  [javascript]
class UnionFind {
  constructor(n) {
    this.p = new Array(n).fill(null).map((_, i) => i)
    this.height = new Array(n).fill(0)
    this.size = new Array(n).fill(1)
  }

  unite(a, b) {
    this.link(this.findSet(a), this.findSet(b))
  }

  link(a, b) {
    if (a === b) return null

    if (this.height[a] > this.height[b]) {
      this.p[b] = a
      this.size[a] += this.size[b]
    } else {
      this.p[a] = b
      this.size[b] += this.size[a]

      if (this.height[a] === this.height[b]) {
        this.height[b]++
      }
    }
  }

  findSet(x) {
    if (this.p[x] === x) return x
    return this.findSet(this.p[x])
  }
}

const main = (input) => {
  input = input.trim().split('\n')
  const [n,] = input.shift().split(' ').map(Number)
  input = Array.from(new Set(input))

  const uf = new UnionFind(n+1)

  for (let i=0; i<input.length; i++) uf.unite(...input[i].split(' ').map(Number))
  
  return console.log(uf.size.reduce((a, b) => Math.max(a, (b || 0)), 0))
}

process.env.MYTEST
  ? (process.env.MYTEST === 'test' ? test() : main(require('fs').readFileSync('dev/stdin', 'utf8')))
  : main(require('fs').readFileSync('/dev/stdin', 'utf8'))
//  [javascript]
(async () => {
    let input = '';
    for await (const chunk of process.stdin) input += chunk;
    let lines = input.split(/\n/);
    const [n, m] = lines.shift().split(/\s+/);

    lines = lines.slice(0, m);
    
    let friends = [];
    lines.forEach(line => {
        const [a, b] = line.split(/\s+/).map(v => v - 1);
        const groups = friends.filter(f => f.has(a) || f.has(b));
        if(groups.length == 0){
            groups[0] = new Set();
            friends.push(groups[0]);
        }
        groups[0].add(a);
        groups[0].add(b);
        if(groups.length > 1){
            console.log(groups);
            let group = groups[0]
            for (let i = 1; i < groups.length; i++) {
                friends.splice(friends.indexOf(groups[i], 1));
                groups[i].forEach(f => {
                    group.add(f);
                });
            }
        }
    });

    console.log(friends.reduce((count, group) => Math.max(count, group.size), 0));

})();
//  [javascript]
(async () => {
    let input = '';
    for await (const chunk of process.stdin) input += chunk;
    let lines = input.split(/\n/);
    const [n, m] = lines.shift().split(/\s+/);

    lines = lines.slice(0, m);
    
    let friends = [];
    lines.forEach(line => {
        const [a, b] = line.split(/\s+/).map(v => v - 1);
        const groups = friends.filter(f => f.includes(a) || f.includes(b));
        if(groups.length == 0){
            friends.push([a, b]);
        }else{
            if(!groups[0].includes(a)){
                groups[0].push(a);
            }
            if(!groups[0].includes(b)){
                groups[0].push(b);
            }
        }
        if(groups.length > 1){
            console.log(groups);
            let index = friends.indexOf(groups[0]);
            let group = groups[0]
            for (let i = 1; i < groups.length; i++) {
                friends.splice(friends.indexOf(groups[i], 1));
                group = group.join(groups[i]);
            }
            friends[index] = group;
        }
    });

    let groupCount = 0;
    friends.forEach(group => {
        const friend = new Set();
        for(const e of group){
            friend.add(e);
        }
        groupCount = Math.max(groupCount, friend.size);
    })

    console.log(groupCount);

})();
//  [javascript]
(async () => {
    let input = '';
    for await (const chunk of process.stdin) input += chunk;
    let lines = input.split(/\n/);
    const [n, m] = lines.shift().split(/\s+/);

    lines = lines.slice(0, m);
    
    let friends = [];
    lines.forEach(line => {
        const [a, b] = line.split(/\s+/).map(v => v - 1);
        const groups = friends.filter(f => f.includes(a) || f.includes(b));
        if(groups.length == 0){
            friends.push([a, b]);
        }else{
            if(!groups[0].includes(a)){
                groups[0].push(a);
            }
            if(!groups[0].includes(b)){
                groups[0].push(b);
            }
        }
        if(groups.length > 1){
            console.log(groups);
            let index = friends.indexOf(groups[0]);
            let group = groups[0]
            for (let i = 1; i < groups.length; i++) {
                friends.splice(friends.indexOf(groups[i], 1));
                group = group.join(groups[i]);
            }
            friends[index] = group;
        }
    });

    console.log(friends.reduce((count, friend) => Math.max(count, friend.length), 0));

})();
//  [go]
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {
	n, m := readI(), readI()
	uf := newUF(n)
	for i := 0; i < m; i++ {
		uf.unite(readI()-1, readI()-1)
	}
	fmt.Println(-min(uf.d))
}

func min(a []int) int {
	l := len(a)
	m := a[0]
	for i := 1; i < l; i++ {
		if a[i] < m {
			m = a[i]
		}
	}
	return m
}

//Union-Find
type unionFind struct {
	d []int
}

func newUF(n int) *unionFind {
	d := make([]int, n)
	for i := range d {
		d[i] = -1
	}
	u := unionFind{d}
	return &u
}

func (u *unionFind) root(a int) int {
	if u.d[a] < 0 {
		return a
	}
	u.d[a] = u.root(u.d[a])
	return u.d[a]
}

func (u *unionFind) unite(a, b int) {
	ar, br := u.root(a), u.root(b)
	if ar == br {
		return
	}
	if -u.d[ar] < -u.d[br] {
		ar, br = br, ar
	}
	u.d[ar] += u.d[br]
	u.d[br] = ar
}

func (u *unionFind) isSame(a, b int) bool {
	return u.root(a) == u.root(b)
}

func (u *unionFind) size(a int) int {
	return -u.d[u.root(a)]
}

/*-----------Input utils-----------*/

var sc = bufio.NewScanner(os.Stdin)

func init() {
	if len(os.Args) >= 2 {
		if os.Args[1] == "debug" {
			debug()
		}
	}
	const buf = 200100
	sc.Split(bufio.ScanWords)
	sc.Buffer(make([]byte, buf), buf)
}

func debug() {
	testFile, err := os.Open("./test/sample-1.in")
	if err != nil {
		fmt.Fprintln(os.Stderr, "There is no testfile.")
		os.Exit(1)
	}
	sc = bufio.NewScanner(testFile)
}

func readS() string {
	sc.Scan()
	return sc.Text()
}

func readR() []rune {
	return []rune(readS())
}

func readI() int {
	i, _ := strconv.Atoi(readS())
	return i
}

func readF() float64 {
	f, _ := strconv.ParseFloat(readS(), 64)
	return f
}
//  [go]
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

var scanner = bufio.NewScanner(os.Stdin)

func NextStr() string {
	scanner.Scan()
	return scanner.Text()
}

func NextInt() int {
	i, _ := strconv.Atoi(NextStr())
	return i
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func sort(x, y int) (int, int) {
	if x > y {
		return y, x
	}
	return x, y
}

func main() {
	scanner.Split(bufio.ScanWords)
	n, m := NextInt(), NextInt()
	groups := make([]int, n)
	belongings := make([]int, n)
	members := make([][]int, n)
	// 初期は各メンバーは一人グループ
	for i := 0; i < n; i++ {
		groups[i] = 1
		belongings[i] = i
		members[i] = []int{i}
	}

	var ans int

	for i := 0; i < m; i++ {
		a, b := NextInt()-1, NextInt()-1
		a, b = sort(a, b)
		belong := belongings[a]
		target := belongings[b]
		if target != belong {
			// aの所属グループにbのメンバーを所属させる
			groups[belong] += groups[b]
			oldmembers := members[target]
			members[belong] = append(members[belong], members[target]...)
			groups[target] = 0
			members[target] = []int{}
			// 旧メンバーの所属先をaの所属先に更新
			for _, member := range oldmembers {
				belongings[member] = belong
			}
			ans = max(ans, groups[belong])
		}
	}
	fmt.Println(ans)
}
//  [ruby]
class UnionFind
  def initialize(n)
    @parents = Array.new(n, -1)
  end
  def find(x)
    @parents[x] < 0 ? x : @parents[x] = find(@parents[x])
  end
  def parents
    @parents
  end
  def union(x, y)
    x = find(x)
    y = find(y)
    return if x == y
    if @parents[x] > @parents[y]
      x, y = y, x
    end
    @parents[x] += @parents[y]
    @parents[y] = x
  end  
end

n, m = gets.split.map(&:to_i)
u = UnionFind.new(n)
m.times do
  a, b = gets.split.map(&:to_i)
  u.union(a - 1, b - 1)
end
puts -u.parents.min
//  [ruby]
def find(parent, i)
  t = parent[i]
  return i if t < 0
  t = find(parent, t)
  parent[i] = t
end

def unite(parent, i, j)
  i = find(parent, i)
  j = find(parent, j)
  return if i == j
  parent[j] += parent[i]
  parent[i] = j
end

n, m = gets.split.map(&:to_i)
parent = [-1] * n
m.times do
  a, b = gets.split.map{ |e| e.to_i - 1 }
  unite(parent, a, b)
end
puts -parent.min
//  [ruby]
class UnionFind
  def initialize(n)
    @n = n
    @par = Array.new(@n, -1)
  end
  def find(x)
    @par[x] < 0 ? x : @par[x] = find(@par[x])
  end
  def union(a, b)
    pa, pb = find(a), find(b)
    return if pa == pb
    if pa < pb then
      @par[pa] += @par[pb]
      @par[pb] = pa
    else
      @par[pb] += @par[pa]
      @par[pa] = pb
    end
  end
  def max_size
    -@par.min
  end
  def show
    p @par
  end
end

N, M = gets.chomp.split(" ").map(&:to_i)
uf = UnionFind.new(N)
(0...M).map{
  a, b = gets.chomp.split(" ").map(&:to_i)
  uf.union(a-1, b-1)
}

puts uf.max_size
//  [ruby]
require 'set'
n,m = gets.split.map(&:to_i)
check = Array.new(n+1){Set.new}
max = 1
m.times do
  a,b = gets.split.map(&:to_i)
  check[b].add?(a)
  check[a].add?(b)
end
ans = 0
check.each do |c|
  ans = [ans,c.length+1].max
end
p ans
//  [ruby]
require 'set'
n,m = gets.split.map(&:to_i)
groups = {}
h = {}
m.times do
  a, b = gets.split.map(&:to_i)
  a, b = [a, b].sort

  if g = h[a] || h[b]
    g << a
    g << b
    h[a] = g
    h[b] = g
  else
    s = Set.new
    s << a
    s << b
    h[a] = s
    h[b] = s
  end
end

sets = h.keys.map do |i|
  h[i]
end.uniq

sets.sort_by! do |s|
  s.size
end

puts sets.last.size
//  [ruby]
n,m = gets.split.map(&:to_i)
groups = {}
h = {}
m.times do
  a, b = gets.split.map(&:to_i)
  a, b = [a, b].sort
  group = h[a] || h[b]
  if group
    h[a] = group
    h[b] = group
    groups[group] << a
    groups[group] << b
  else
    h[a] = a
    h[b] = a
    groups[a] = [a, b]
  end
end

groups.keys.each do |k|
  groups[k].uniq!
end

ans = -Float::INFINITY

groups.keys.each do |k|
  ans = [ans, groups[k].size].max
end

puts ans
//  [rust]
#![allow(dead_code)]
#![allow(unused)]
use proconio::input;

mod union_find {
    pub struct UnionFind { pub(self) list: Vec<i32> }
    impl UnionFind {
        pub fn new(size: usize) -> UnionFind { UnionFind{ list: vec![-1; size] } }
        pub fn root(&self, n: usize) -> usize { if self.list[n] < 0 { n } else { self.root(self.list[n] as usize) } }
        pub fn size_at(&self, n: usize) -> i32 { std::cmp::max(0, -self.list[n]) }
        pub fn unite(&mut self, x: usize, y: usize) {
             let (mut x_root, mut y_root) = (self.root(x), self.root(y));
              if(x_root == y_root) { return; } 
              if(self.list[x_root] > self.list[y_root]) { std::mem::swap(&mut x_root, &mut y_root); } 
              self.list[x_root] += self.list[y_root]; 
              self.list[y_root] = x_root as i32; }
        pub fn are_in_same_tree(self, x: usize, y: usize) -> bool { self.root(x) == self.root(y) }  
    }
}

fn main() {
    input!{n: usize, m: usize}
    let mut uf = union_find::UnionFind::new(n);
    for _ in 0..m {
        input!{a: usize, b: usize}
        uf.unite(a - 1, b - 1);
    }
    let mut max = 0;
    for i in 0..n {
        max = std::cmp::max(max, uf.size_at(i));
    }
    println!("{}", max);
}
//  [rust]
use proconio::marker::Usize1;
fn main() {
    proconio::input! {
        n: usize,
        m: usize,
        ab: [(Usize1,Usize1);m],
    }
    let mut uf=vec![-1;n];
    for (a,b) in ab {
        unite(&mut uf, a, b);
    }
    println!("{}",(0..n).map(|i|count(&mut uf,i)).max().unwrap());
}
fn find(uf: &mut Vec<i32>, i: usize) -> usize {
    if uf[i]<0 {
        i
    }
    else {
        uf[i]=find(uf, uf[i]as usize)as i32;
        uf[i]as usize
    }
}
fn unite(uf: &mut Vec<i32>, i: usize, j: usize) {
    let mut i=find(uf, i);
    let mut j=find(uf, j);
    if i==j {
        return;
    }
    if uf[i]>uf[j] {
        std::mem::swap(&mut i, &mut j);
    }
    uf[i]+=uf[j];
    uf[j]=i as i32;
}
fn count(uf: &mut Vec<i32>, i: usize) -> usize {
    let i=find(uf, i);
    (-uf[i])as usize
}
//  [rust]
struct UnionFind {
    root: Vec<usize>,
    rank: Vec<usize>,
    sizes: Vec<usize>,
}

impl UnionFind {
    fn new(n: usize) -> UnionFind {
        let mut vec = vec![0;n];
        for i in 0..n {
            vec[i] = i;
        }
        UnionFind {
            root: vec,
            rank: vec![0;n],
            sizes: vec![1;n],
        }
    }

    fn find(&mut self, x: usize) -> usize {
        if self.root[x] == x { return x }
        self.root[x] = self.find(self.root[x]);
        self.root[x]
    }

    fn unite(&mut self, x: usize, y: usize) -> () {
        let x = self.find(x);
        let y = self.find(y);
        if x == y { return }
        if self.rank[x] < self.rank[y] {
            self.root[x] = y;
            self.sizes[y] += self.sizes[x];
        } else {
            self.root[y] = x;
            self.sizes[x] += self.sizes[y];
            if self.rank[x] == self.rank[y] {
                self.rank[x] += 1;
            }
        }
    }

    fn same(&mut self, x: usize, y: usize) -> bool {
        self.find(x) == self.find(y)
    }

    fn size(&mut self, x: usize) -> usize{
        let f = self.find(x);
        self.sizes[f]
    }

    fn roots(&mut self, n: usize) -> Vec<usize> {
        let mut vec = vec![];
        for i in 0..n {
            if self.root[i] == i {
                vec.push(self.root[i]);
            }
        }
        vec
    }
}
//  [rust]
use proconio::{input, fastout};
use proconio::marker::Usize1;
use std::collections::HashSet;

pub struct GraphL {
    g: Vec<HashSet<usize>>,
    n: usize,
}
impl GraphL {
    pub fn dfs(&self, s: usize) -> usize {
        let mut stack = Vec::new();
        let mut visit = vec![false; self.n];
        stack.push(s);
        let mut res = 0;
        let mut depth = 1;
        while let Some(&u) = stack.last() {
            visit[u] = true;
            let v = self.g[u].iter().find(|&i| !visit[*i]);
            if let Some(v) = v {
                stack.push(*v);
                depth += 1;
            } else {
                stack.pop();
                res = std::cmp::max(res, depth);
                depth = 0;
            }
        }
        res
    }
}

#[fastout]
fn main() {
    input! {
        n: usize,
        m: usize,
        v: [(Usize1,Usize1);m]
    }
    let mut g = vec![HashSet::new();n];
    for (a,b) in v {
        g[a].insert(b);
        g[b].insert(a);
    }
    let g = GraphL {
        g, n,
    };
    let mut res = 0;
    for i in 0..n {
        res = std::cmp::max(res, g.dfs(i))
    }
    println!("{}", res);
}
//  [rust]
use proconio::input;

struct UnionFind {
    parent: Vec<usize>,
    rank: Vec<usize>,
}

impl UnionFind {
    fn new(n: usize) -> Self {
        let mut parent = vec![0; n];
        (0..n).for_each(|i| parent[i] = i);
        let rank = vec![0; n];
        UnionFind { parent, rank }
    }

    fn root(&mut self, x: usize) -> usize {
        if x == self.parent[x] {
            x
        } else {
            self.parent[x] = self.root(self.parent[x]);
            self.parent[x]
        }
    }

    fn same(&mut self, x: usize, y: usize) -> bool {
        self.root(x) == self.root(y)
    }

    fn merge(&mut self, x: usize, y: usize) {
        let x = self.parent[x];
        let y = self.parent[y];

        if x == y {
            return;
        }

        if self.rank[x] < self.rank[y] {
            self.parent[x] = y;
        } else {
            self.parent[y] = x;
            if self.rank[x] == self.rank[y] {
                self.rank[x] += 1;
            }
        }
    }

    fn each_size(&self) -> Vec<usize> {
        use std::collections::HashMap;
        let mut map: HashMap<usize, usize> = HashMap::new();
        for i in self.parent.iter() {
            let count = map.entry(*i).or_insert(0);
            *count += 1;
        }
        let v = map.iter().map(|(_, &b)| b).collect();
        v
    }
}

fn main() {
    input! {
        n: usize,
        m: usize
    }

    let mut union = UnionFind::new(n);
    for _ in 0..m {
        input! {
            x: usize,
            y: usize
        }
        union.merge(x - 1, y - 1);
    }
    println!("{}", union.each_size().iter().max().unwrap());
}
//  [swift]
func readTwoInts(separator: String.Element = " ") -> (a: Int, b: Int) {
    let ints = readLine()!.split(separator: separator).map { Int($0)! }
    return (a: ints[0], b: ints[1])
}

func mainD() {
    let (N, M) = readTwoInts()
    let pairs = (0..<M).map { _ in readTwoInts() }

    var groups: [Set<Int>] = (1...N).map { Set(arrayLiteral: $0) }
    pairs.forEach { pair in
        groups[pair.a - 1].insert(pair.b)
        groups[pair.b - 1].insert(pair.a)
    }

    pairs.forEach { pair in
        for id in groups[pair.a - 1] {
            groups[pair.b - 1].insert(id)
        }

        for id in groups[pair.b - 1] {
            groups[pair.a - 1].insert(id)
        }
    }

    // それぞれの直接の友達をセットアップ(片側だけ)
//    var persons: [Person] = (1...N).map { Person(id: $0) }
//    pairs.forEach { pair in
//        persons[pair.a - 1].friends.insert(pair.b)
//        persons[pair.b - 1].friends.insert(pair.a)
//    }

//    var groups: [Set<Int>] = []
//    for person in persons {
//        var needNewGroup = true
//
//        for i in (0..<groups.count) {
//            if !groups[i].intersection(person.friends).isEmpty {
//                needNewGroup = false
//
//                groups[i].insert(person.id)
//                for id in person.friends {
//                    groups[i].insert(id)
//                }
//                break
//            }
//        }
//
//        if needNewGroup {
//            var newGroup = Set(person.friends)
//            newGroup.insert(person.id)
//            groups.append(newGroup)
//        }
//    }

    // 最大人数の判定
    print(groups.map { $0.count }.max()!)
}
mainD()
//  [swift]
func readTwoInts(separator: String.Element = " ") -> (a: Int, b: Int) {
    let ints = readLine()!.split(separator: separator).map { Int($0)! }
    return (a: ints[0], b: ints[1])
}

func mainD() {
    let (N, M) = readTwoInts()
    let pairs = (0..<M).map { _ in readTwoInts() }

    var groups: [Set<Int>] = (1...N).map { Set(arrayLiteral: $0) }
    pairs.forEach { pair in
        groups[pair.a - 1].insert(pair.b)
        groups[pair.b - 1].insert(pair.a)
    }

    // それぞれの直接の友達をセットアップ(片側だけ)
//    var persons: [Person] = (1...N).map { Person(id: $0) }
//    pairs.forEach { pair in
//        persons[pair.a - 1].friends.insert(pair.b)
//        persons[pair.b - 1].friends.insert(pair.a)
//    }

//    var groups: [Set<Int>] = []
//    for person in persons {
//        var needNewGroup = true
//
//        for i in (0..<groups.count) {
//            if !groups[i].intersection(person.friends).isEmpty {
//                needNewGroup = false
//
//                groups[i].insert(person.id)
//                for id in person.friends {
//                    groups[i].insert(id)
//                }
//                break
//            }
//        }
//
//        if needNewGroup {
//            var newGroup = Set(person.friends)
//            newGroup.insert(person.id)
//            groups.append(newGroup)
//        }
//    }

    // 最大人数の判定
    print(groups.map { $0.count }.max()!)
}
mainD()
//  [swift]
func readTwoInts(separator: String.Element = " ") -> (a: Int, b: Int) {
    let ints = readLine()!.split(separator: separator).map { Int($0)! }
    return (a: ints[0], b: ints[1])
}

func mainD() {
    let (N, M) = readTwoInts()
    let pairs = (0..<M).map { _ in readTwoInts() }

    var groups: [Set<Int>] = (1...N).map { Set(arrayLiteral: $0) }
    pairs.forEach { pair in
        groups[pair.a - 1].insert(pair.b)
        groups[pair.b - 1].insert(pair.a)
    }

    pairs.forEach { pair in
        for id in groups[pair.a - 1] {
            groups[pair.b - 1].insert(id)
        }
    }

    // それぞれの直接の友達をセットアップ(片側だけ)
//    var persons: [Person] = (1...N).map { Person(id: $0) }
//    pairs.forEach { pair in
//        persons[pair.a - 1].friends.insert(pair.b)
//        persons[pair.b - 1].friends.insert(pair.a)
//    }

//    var groups: [Set<Int>] = []
//    for person in persons {
//        var needNewGroup = true
//
//        for i in (0..<groups.count) {
//            if !groups[i].intersection(person.friends).isEmpty {
//                needNewGroup = false
//
//                groups[i].insert(person.id)
//                for id in person.friends {
//                    groups[i].insert(id)
//                }
//                break
//            }
//        }
//
//        if needNewGroup {
//            var newGroup = Set(person.friends)
//            newGroup.insert(person.id)
//            groups.append(newGroup)
//        }
//    }

    // 最大人数の判定
    print(groups.map { $0.count }.max()!)
}
mainD()
//  [typescript]
// @ts-ignore
import * as fs from 'fs';
import { kMaxLength } from 'buffer';

// メイン
var g_root: number[];
var g_count: number[];

function main(input: string[]) {
    var work0: number[] = input.shift().split(" ").map(x => Number(x));
    var n: number = work0[0];
    var m: number = work0[1];
    var node: number[][] = input.map(x => x.split(" ").map(x => Number(x) - 1));
    g_root = new Array(n).fill(-1);
    g_count = new Array(n).fill(1);
    node.forEach(value => {
        var a: number = value[0];
        var b: number = value[1];
        var roota: number = getRoot(a);
        var rootb: number = getRoot(b);
        if (roota == rootb) return;
        if (roota > rootb) [roota, rootb] = [rootb, roota];
        mergeRoot(roota, rootb);
    });
    // TODO Math.max(...)は使ってはダメ、スプレッド構文はスタックに展開するのでスタックがあふれる
    // console.log(Math.max(g_cound));
    console.log(Math_max(g_count));
}

function Math_max(arr: number[]) {
    return arr.reduce(function(x, y) {
        return Math.max(x, y);
    });
}
function getRoot(index: number) {
    if (g_root[index] < 0) {
        return index;
    } else {
        var work0: number = getRoot(g_root[index]);
        g_root[index] = work0;
        return work0
    }
}

function mergeRoot(root0: number, root1: number) {
    g_count[root0] += g_count[root1];
    g_count[root1] = 0;
    g_root[root1] = root0;
}

// エントリポイント
// - OSによるパラメタの処理の違いを吸収
function entrypoint() {
    try {
        var input = fs.readFileSync("/dev/stdin", "utf8").trim().split("\n");
        console.debug = function () { };
        main(input);
    }
    catch (ex) {
        console.log("----");
        console.log("file='%s'", __filename.split("\\").slice(-1)[0]);
        console.log("----");
        const lines: string[] = [];
        // @ts-ignore
        const reader = require('readline').createInterface({
            // @ts-ignore
            input: process.stdin,
            // @ts-ignore
            output: process.stdout
        });
        reader.on('line', function (line: string) {
            lines.push(line);
        });
        reader.on('close', function () {
            input = lines;
            console.log("input=%o", input);
            console.time();
            console.log("----")
            main(input);
            console.log("----")
            console.timeEnd();
        });
    }
}
entrypoint();