Go: package main

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

var rdr = bufio.NewReaderSize(os.Stdin, 1000000)

func readLine() string {
    buf := make([]byte, 0, 1000000)
    for {
        l, p, e := rdr.ReadLine()
        if e != nil {
            panic(e)
        }
        buf = append(buf, l...)
        if !p {
            break
        }
    }
    return string(buf)
}

func toInt(str string) int  {
    n, _ := strconv.Atoi(str)
    return n
}

func abs(a int) int {
    return int(math.Abs(float64(a)))
}

func getPar(x int, parent[1000]int) int {
    if parent[x] == x {
        return x
    } else {
        parent[x] = getPar(parent[x], parent)
        return parent[x]
    }
}

func main() {
    nm := strings.Split(readLine(), " ")
    n := toInt(nm[0])
    m := toInt(nm[1])
    var parent [1000]int
    for i := 0;i < n; i++ {
        parent[i] = i
    }


    for i := 0; i < m; i++ {
        ab := strings.Split(readLine(), " ")
        pa := getPar(toInt(ab[0]) - 1, parent)
        pb := getPar(toInt(ab[1]) - 1, parent)
        parent[pb] = pa
    }

    cities := make(map[int]int)
    villageCnt := 0
    for i := 0;i < n; i ++ {
        pi := getPar(i, parent)
        if i != pi {
            cities[pi] = 1
        } else {
            villageCnt ++
        }
    }
    cityCnt := len(cities)
    fmt.Println(abs(cityCnt * 2 - villageCnt))
}

C++: /* template.cpp {{{ */
#include <bits/stdc++.h>
using namespace std;
 
// #define int long long
#define GET_MACRO(a, b, c, d, NAME, ...) NAME
#define REP1(n) REP2(i_, n)
#define REP2(i, n) REP3(i, 0, n)
#define REP3(i, a, b) REP4(i, a, b, 1)
#define REP4(i, a, b, s) for (long long i = (a); i < (long long)(b); i += (long long)(s))
#define RREP1(n) RREP2(i_, n)
#define RREP2(i, n) RREP3(i, 0, n)
#define RREP3(i, a, b) RREP4(i, a, b, 1)
#define RREP4(i, a, b, s) for (long long i = (b) - 1; i >= (long long)(a);  i -= (long long)(s))
#define rep(...) GET_MACRO(__VA_ARGS__, REP4, REP3, REP2, REP1)(__VA_ARGS__)
#define rrep(...) GET_MACRO(__VA_ARGS__, RREP4, RREP3, RREP2, RREP1)(__VA_ARGS__)
#define fs first
#define sc second
#define all(c) std::begin(c), std::end(c)
#define pcnt(x) __builtin_popcountll(x)
#define each(x, c) for (auto &&x : c)
#define endl "\n"
#define y0 y0_
#define y1 y1_
#define yn yn_
 
#define TMP_T template<typename T>
#define TMP_TU template<typename T, typename U>
#define TMP_Ts template<typename ...T>
#define TMP_NTs template<size_t N, typename ...T>
#define TMP_CT template<bool C, typename T = void>
 
#ifndef DEBUG
#define cerr no_output
struct NoOutput : ostream {
  TMP_T ostream &operator<<(const T &){ return *this; }
} no_output;
#endif
 
using uint = unsigned;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
TMP_T using PQL = priority_queue<T, vector<T>, greater<T>>;
TMP_T using PQG = priority_queue<T>;
TMP_CT using enable_if_t = typename enable_if<C, T>::type;
 
const ll LLINF = 1e18 + 10;
#ifndef int
const int INF = 1e9 + 10;
#else
const int INF = LLINF;
#endif
 
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};
const int dy[] = {0, -1, 0, 1, -1, -1, 1, 1};
 
TMP_T inline constexpr T sq(T x){ return x * x; }
TMP_TU inline T& chmin(T &x, U y){ if (x > y) x = y; return x; }
TMP_TU inline T& chmax(T &x, U y){ if (x < y) x = y; return x; }
 
TMP_NTs enable_if_t<(N >= sizeof...(T))> input_tuple(istream &, tuple<T...> &){}
TMP_NTs enable_if_t<(N < sizeof...(T))> input_tuple(istream &is, tuple<T...> &x){ is >> get<N>(x); input_tuple<N + 1, T...>(is, x); }
TMP_Ts ostream &operator>>(istream &is, tuple<T...> &x){ input_tuple<0, T...>(is, x); return is; }
TMP_TU ostream &operator>>(istream &is, pair<T, U> &x){ return is >> x.first >> x.second; }
TMP_NTs enable_if_t<(N >= sizeof...(T))> print_tuple(ostream &, const tuple<T...> &){}
TMP_NTs enable_if_t<(N < sizeof...(T))> print_tuple(ostream &os, const tuple<T...> &x){ os << (N > 0 ? " " : "") << get<N>(x); print_tuple<N + 1, T...>(os, x); }
TMP_Ts ostream &operator<<(ostream &os, const tuple<T...> &x){ print_tuple<0, T...>(os, x); return os; }
TMP_TU ostream &operator<<(ostream &os, const pair<T, U> &x){ return os << x.first << " " << x.second; }
 
#undef TMP_T
#undef TMP_TU
#undef TMP_Ts
#undef TMP_NTs
#undef TMP_CT

ll gcd(ll a, ll b){ return b ? gcd(b, a % b) : a; }
ll lcm(ll a, ll b){ return a / gcd(a, b) * b; }
tuple<ll, ll, ll> extgcd(ll a, ll b){
  if (b){
    ll g, x, y;
    tie(g, x, y) = extgcd(b, a % b);
    return make_tuple(g, y, x - a / b * y);
  }
  return make_tuple(a, 1, 0);
}
ll invmod(ll a, ll m = 1000000007){
  ll g, x;
  tie(g, x, ignore) = extgcd(a, m);
  return g == 1 ? (x + m) % m : 0;
}

inline ll in(){ ll x; cin >> x; return x; }
 
struct prepare {
  prepare(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(12);
    cerr << fixed << setprecision(12);
  }
} prepare_;
/* }}} */
/* union_find.cpp {{{ */
class UnionFind {
public:
  UnionFind(int n = 0): cnt(n), par(n, -1){}
  int root(int x) const { return par[x] < 0 ? x : par[x] = root(par[x]); }
  bool same(int x, int y) const { return root(x) == root(y); }
  int size(int x) const { return -par[root(x)]; }
  int count() const { return cnt; }
  bool merge(int x, int y){
    if ((x = root(x)) == (y = root(y))) return false;
    if (par[x] > par[y]) swap(x, y);
    par[x] += par[y];
    par[y] = x;
    cnt--;
    return true;
  }
private:
  int cnt;
  mutable vector<int> par;
};
/* }}} */

int c[1000];

signed main()
{
  int n, m;
  cin >> n >> m;
  UnionFind uf(n);
  rep(m) uf.merge(in() - 1, in() - 1);
  rep(i, n) c[uf.root(i)]++;
  int s = 0;
  rep(i, n){
    if (c[i] == 1) s++;
    else if (c[i] > 1) s--;
  }
  cout << abs(s) << endl;
}

C++: #include <iostream>
#include <cstdlib>
using namespace std;
int main(){

  int n,m,c[1001]={},flag[1001]={},r0=0,r1=0;
  cin>>n>>m;
  for(int i=1,a,b;i<=m;i++){
    cin>>a>>b;
    if(!c[a]){
      if(!c[b]){
      c[a]=i;
      c[b]=i;
      }
      else c[a]=c[b];
    }
    else {
      if(!c[b]){
        c[b]=c[a];
      } else {
        for(int j=1;j<=n;j++) if(c[j]==c[b]) c[j]=c[a];
      }
    }
  }
  for(int i=1;i<=n;i++){
    if(!c[i]) r1++;
    else if(!flag[c[i]]){
      flag[c[i]]=1;
      r0++;
    }
  }
  cout<<abs(r0-r1)<<endl;
  return 0;
}

C++: #include <bits/stdc++.h>
typedef long long LL;
#define SORT(c) sort((c).begin(),(c).end())

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

using namespace std;
struct Unionfind {
  vector<int> size;
  vector<int> par;
  
  Unionfind( int n ) :  size(n, 1), par(n) {
    iota( par.begin() , par.end() , 0 );
  }
  
  int find( int x ) {
    if ( par[x] == x ) return x;
    return par[x] = find( par[x] );
  }
  
  bool unite( int x , int y ) {
    x = find(x);
    y = find(y);
    if ( x == y ) return false;
    
    if ( size[y] < size[x] ) swap( x , y );
    
    par[x] = y;
    size[y] += size[x];
    
    return true;
  }
  
  bool same( int x , int y ) {
    return find(x) == find(y);
  }
};

int main() {
  int n, q;
  cin >> n >> q;
  Unionfind uf(n);
  int x, y;
  REP(i,q) {
    cin >> x >> y;
    uf.unite(x-1, y-1);
  }
  set<int> sum,ci;
  REP(i,n){
    if(uf.find(i)==i) sum.insert(i);
    else ci.insert(uf.find(i));
  }
  cout << abs(int(sum.size())-2*int(ci.size())) << endl;
  return 0;
}