#include <algorithm>
#include <iostream>
#include <math.h>
#include <numeric>
#include <queue>
#include <stdio.h>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

struct UnionFind {
  vector<int> parent;
  int N;
  UnionFind(int n) : N(n) { // メンバイニシャライザを実行している
    for (int i = 0; i < N; i++) {
      parent[i] = i;
    }
  }
  int getParent(int x) { return parent[x]; }

  int root(int x) {
    if (parent[x] == x) {
      return x;
    } else {
      parent[x] = root(parent[x]); // 親の付け替え(ならし)
      return parent[x];
    }
  }
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx != ry) {
      parent[ry] = rx;
    }
  }
  bool same(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int main(int argc, char *argv[]) {
  int N, M;
  scanf("%d %d", &N, &M);
  vector<int> A(M);
  vector<int> B(M);
  UnionFind tree(N);
  for (int i = 0; i < M; i++) {
    scanf("%d %d", &A[i], &B[i]);
    if (A[i] > B[i]) {
      int tmp;
      tmp = B[i];
      B[i] = A[i];
      A[i] = tmp;
    }
    tree.unite(A[i] - 1, B[i] - 1);
  }
  int count = 0;
  for (int i = 0; i < N; i++) {
    if (tree.getParent(i) == i) {
      count++;
    }
  }
  printf("%d\\n", count - 1);
}

#include <algorithm>
#include <iostream>
#include <math.h>
#include <numeric>
#include <queue>
#include <stdio.h>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

struct UnionFind {
  vector<int> parent;
  int N;
  UnionFind(int n) : parent(n), N(n) { // メンバイニシャライザを実行している
    for (int i = 0; i < n; i++) {
      parent[i] = i;
    }
  }
  int getParent(int x) { return parent[x]; }

  int root(int x) {
    if (parent[x] == x) {
      return x;
    } else {
      parent[x] = root(parent[x]); // 親の付け替え(ならし)
      return parent[x];
    }
  }
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx != ry) {
      parent[ry] = rx;
    }
  }
  bool same(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int main(int argc, char *argv[]) {
  int N, M;
  scanf("%d %d", &N, &M);
  vector<int> A(M);
  vector<int> B(M);
  UnionFind tree(N);
  for (int i = 0; i < M; i++) {
    scanf("%d %d", &A[i], &B[i]);
    if (A[i] > B[i]) {
      int tmp;
      tmp = B[i];
      B[i] = A[i];
      A[i] = tmp;
    }
    tree.unite(A[i] - 1, B[i] - 1);
  }
  int count = 0;
  for (int i = 0; i < N; i++) {
    if (tree.getParent(i) == i) {
      count++;
    }
  }
  printf("%d\\n", count - 1);
}


#include <algorithm>
#include <iostream>
#include <math.h>
#include <numeric>
#include <queue>
#include <stdio.h>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

struct UnionFind {
  vector<int> parent;
  UnionFind(int N) : parent(N) {
    for (int i = 0; i < N; i++) {
      parent[i] = i;
    }
  }
  int getParent(int x) { return parent[x]; }

  int root(int x) {
    if (parent[x] == x) {
      return x;
    } else {
      return root(parent[x]);
    }
  }
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx != ry) {
      parent[ry] = rx;
    }
  }
  bool same(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int main(int argc, char *argv[]) {
  int N, M;
  scanf("%d %d", &N, &M);
  vector<int> A(M);
  vector<int> B(M);
  UnionFind tree(N);
  for (int i = 0; i < M; i++) {
    scanf("%d %d", &A[i], &B[i]);
    if (A[i] > B[i]) {
      int tmp;
      tmp = B[i];
      B[i] = A[i];
      A[i] = tmp;
    }
    tree.unite(A[i] - 1, B[i] - 1);
  }
  int count = 0;
  for (int i = 0; i < N; i++) {
    if (tree.getParent(i) == i) {
      count++;
    }
  }
  printf("%d\\n", count - 1);
}

#include <algorithm>
#include <iostream>
#include <math.h>
#include <numeric>
#include <queue>
#include <stdio.h>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

struct UnionFind {
  vector<int> parent;
  UnionFind(int N) : parent(N) {
    for (int i = 0; i < N; i++) {
      parent[i] = i;
    }
  }
  int getParent(int x) { return parent[x]; }

  int root(int x) {
    if (parent[x] == x) {
      return x;
    } else {
      parent[x] = root(parent[x]);
      return parent[x];
    }
  }
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx != ry) {
      parent[ry] = rx;
    }
  }
  bool same(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int main(int argc, char *argv[]) {
  int N, M;
  scanf("%d %d", &N, &M);
  vector<int> A(M);
  vector<int> B(M);
  UnionFind tree(N);
  for (int i = 0; i < M; i++) {
    scanf("%d %d", &A[i], &B[i]);
    if (A[i] > B[i]) {
      int tmp;
      tmp = B[i];
      B[i] = A[i];
      A[i] = tmp;
    }
    tree.unite(A[i] - 1, B[i] - 1);
  }
  int count = 0;
  for (int i = 0; i < N; i++) {
    if (tree.getParent(i) == i) {
      count++;
    }
  }
  printf("%d\\n", count - 1);
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1000000007;
#define INF 1LL << 30
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define all(x) (x).begin(), (x).end()

struct UnionFind {
  vector<int> par;

  UnionFind(int n) : par(n, -1) {}
  void init(int n) { par.assign(n, -1); }

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

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

  bool merge(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (par[x] > par[y])
      swap(x, y);
    par[x] += par[y];
    par[y] = x;
    return true;
  }

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

int main() {
  int n, m;
  cin >> n >> m;
  UnionFind uf(n);
  rep(i, m) {
    int a, b;
    cin >> a >> b;
    uf.merge(a, b);
  }

  set<int> s;
  rep(i, n) { s.insert(uf.root(i)); }

  cout << s.size() - 1 << endl;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1000000007;
#define INF 1LL << 30
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define all(x) (x).begin(), (x).end()

struct UnionFind {
  vector<int> par;

  UnionFind(int n) : par(n, -1) {}
  void init(int n) { par.assign(n, -1); }

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

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

  bool merge(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (par[x] > par[y])
      swap(x, y);
    par[x] += par[y];
    par[y] = x;
    return true;
  }

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

int main() {
  int n, m;
  cin >> n >> m;
  UnionFind uf(n);
  rep(i, m) {
    int a, b;
    cin >> a >> b;
    a--, b--;
    uf.merge(a, b);
  }

  set<int> s;
  rep(i, n) { s.insert(uf.root(i)); }

  ll ans = s.size() - 1;
  cout << ans << endl;
}


#include <algorithm>
#include <iostream>
#include <math.h>
#include <numeric>
#include <queue>
#include <stdio.h>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

struct UnionFind {
  vector<int> parent;
  UnionFind(int N) : parent(N) {
    for (int i = 0; i < N; i++) {
      parent[i] = i;
    }
  }
  int getParent(int x) { return parent[x]; }

  int root(int x) {
    if (parent[x] == x) {
      return x;
    } else {
      return root(parent[x]);
    }
  }
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx != ry) {
      parent[rx] = ry;
    }
  }
  bool same(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int main(int argc, char *argv[]) {
  int N, M;
  scanf("%d %d", &N, &M);
  vector<int> A(M);
  vector<int> B(M);
  UnionFind tree(N);
  for (int i = 0; i < M; i++) {
    scanf("%d %d", &A[i], &B[i]);
    if (A[i] > B[i]) {
      int tmp;
      tmp = B[i];
      B[i] = A[i];
      A[i] = tmp;
    }
    tree.unite(A[i] - 1, B[i] - 1);
  }
  int count = 0;
  for (int i = 0; i < N; i++) {
    //		printf("%d\\n", tree.root(i));
  }
  for (int i = 0; i < N; i++) {
    if (tree.getParent(i) == i) {
      count++;
    }
  }
  printf("%d\\n", count - 1);
}

#include <algorithm>
#include <iostream>
#include <math.h>
#include <numeric>
#include <queue>
#include <stdio.h>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;

struct UnionFind {
  vector<int> parent;
  UnionFind(int N) : parent(N) {
    for (int i = 0; i < N; i++) {
      parent[i] = i;
    }
  }
  int getParent(int x) { return parent[x]; }

  int root(int x) {
    if (parent[x] == x) {
      return x;
    } else {
      return parent[x] = root(parent[x]);
    }
  }
  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx != ry) {
      parent[ry] = rx;
    }
  }
  bool same(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int main(int argc, char *argv[]) {
  int N, M;
  scanf("%d %d", &N, &M);
  vector<int> A(M);
  vector<int> B(M);
  UnionFind tree(N);
  for (int i = 0; i < M; i++) {
    scanf("%d %d", &A[i], &B[i]);
    if (A[i] > B[i]) {
      int tmp;
      tmp = B[i];
      B[i] = A[i];
      A[i] = tmp;
    }
    tree.unite(A[i] - 1, B[i] - 1);
  }
  int count = 0;
  for (int i = 0; i < N; i++) {
    if (tree.getParent(i) == i) {
      count++;
    }
  }
  printf("%d\\n", count - 1);
}


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

class DisjointSet {
public:
  vector<int> rank, p;

  DisjointSet() {}
  DisjointSet(int size) {
    rank.resize(size, 0);
    p.resize(size, 0);
    for (int i = 0; i < size; i++) {
      makeSet(i);
    }
  }

  void makeSet(int x) {
    p[x] = x;
    rank[x] = 0;
  }

  void unite(int x, int y) { link(findSet(x), findSet(y)); }

  void link(int x, int y) {
    if (rank[x] > rank[y]) {
      p[y] = x;
    } else {
      p[x] = y;
      if (rank[x] == rank[y]) {
        rank[y]++;
      }
    }
  }

  int findSet(int x) {
    if (x != p[x]) {
      p[x] = findSet(p[x]);
    }
    return p[x];
  }
};

int main() {
  int N, M, A, B;
  cin >> N >> M;
  DisjointSet ds = DisjointSet(N);

  for (int i = 0; i < M; i++) {
    cin >> A >> B;
    ds.unite(A, B);
  }

  set<int> check;
  for (int i = 0; i < N; i++) {
    check.insert(ds.findSet(i));
  }
  cout << check.size() - 1 << endl;
}

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

class DisjointSet {
public:
  vector<int> rank, p;

  DisjointSet() {}
  DisjointSet(int size) {
    rank.resize(size, 0);
    p.resize(size, 0);
    for (int i = 0; i < size; i++) {
      makeSet(i);
    }
  }

  void makeSet(int x) {
    p[x] = x;
    rank[x] = 0;
  }

  void unite(int x, int y) { link(findSet(x), findSet(y)); }

  void link(int x, int y) {
    if (rank[x] > rank[y]) {
      p[y] = x;
    } else {
      p[x] = y;
      if (rank[x] == rank[y]) {
        rank[y]++;
      }
    }
  }

  int findSet(int x) {
    if (x != p[x]) {
      p[x] = findSet(p[x]);
    }
    return p[x];
  }
};

int main() {
  int N, M, A, B;
  cin >> N >> M;
  DisjointSet ds = DisjointSet(N);

  for (int i = 0; i < M; i++) {
    cin >> A >> B;
    ds.unite(A - 1, B - 1);
  }

  set<int> check;
  for (int i = 0; i < N; i++) {
    check.insert(ds.findSet(i));
  }
  cout << check.size() - 1 << endl;
}


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

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

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

  int 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の木を併合
    int rx = root(x);        // xの根をrx
    int ry = root(y);        // yの根をry
    if (rx == ry)
      return; // xとyの根が同じ(=同じ木にある)時はそのまま
    par[rx] =
        ry; // xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
  }

  bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int main(void) {
  int N, M;
  cin >> N >> M;
  UnionFind tree(N);

  for (int i = 0; i < M; i++) {
    int A, B;
    A--;
    B--;
    cin >> A >> B;
    tree.unite(A, B);
  }

  set<int> count{};
  for (int i = 0; i < N; i++) {
    count.insert(tree.root(i));
  }

  cout << count.size() - 1 << endl;
}

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

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

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

  int 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の木を併合
    int rx = root(x);        // xの根をrx
    int ry = root(y);        // yの根をry
    if (rx == ry)
      return; // xとyの根が同じ(=同じ木にある)時はそのまま
    par[rx] =
        ry; // xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
  }

  bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int main(void) {
  int N, M;
  cin >> N >> M;
  UnionFind tree(N);

  for (int i = 0; i < M; i++) {
    int A, B;
    cin >> A >> B;
    A--;
    B--;
    tree.unite(A, B);
  }

  set<int> count{};
  for (int i = 0; i < N; i++) {
    count.insert(tree.root(i));
  }

  cout << count.size() - 1 << endl;
}


#include "stdio.h"
#include <vector>
using namespace std;

vector<int> gra[10001];
int v[10002];

int DFS(int s) {
  v[s] = 1;
  for (int i = 0; i < gra[s].size(); i++) {
    if (v[gra[s][i]] == 0)
      DFS(gra[s][i]);
  }
  return 0;
}

int main() {
  int N, M;
  scanf("%d%d", &N, &M);
  for (int i = 1; i <= N; i++) {
    v[i] = 0;
  }
  int v1, v2;
  for (int i = 0; i < M; i++) {
    scanf("%d%d", &v1, &v2);
    gra[v1].push_back(v2);
    gra[v2].push_back(v1);
  }
  int res = 0;
  for (int i = 1; i <= N; i++)
    if (v[i] == 0) {
      DFS(i);
      res++;
    }
  printf("%d", res - 1);
}

#include "stdio.h"
#include <vector>
using namespace std;

vector<int> gra[100010];
int v[100020];

int DFS(int s) {
  v[s] = 1;
  for (int i = 0; i < gra[s].size(); i++) {
    if (v[gra[s][i]] == 0)
      DFS(gra[s][i]);
  }
  return 0;
}

int main() {
  int N, M;
  scanf("%d%d", &N, &M);
  for (int i = 1; i <= N; i++) {
    v[i] = 0;
  }
  int v1, v2;
  for (int i = 0; i < M; i++) {
    scanf("%d%d", &v1, &v2);
    gra[v1].push_back(v2);
    gra[v2].push_back(v1);
  }
  int res = 0;
  for (int i = 1; i <= N; i++)
    if (v[i] == 0) {
      DFS(i);
      res++;
    }
  printf("%d", res - 1);
}


#include <iostream>
using namespace std;
int dsu[100010];
int fnd(int x) { return (x == dsu[x]) ? x : dsu[x] = fnd(dsu[x]); }
int merge(int u, int v) { dsu[fnd(u)] = fnd(v); }
int main() {
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    dsu[i] = i;
  }
  int x, y, cnt = 0;
  for (int i = 1; i <= m; i++) {
    cin >> x >> y;
    merge(x, y);
  }
  for (int i = 1; i < n; i++) {
    if (fnd(i) != fnd(i + 1)) {
      merge(i, i + 1);
      cnt++;
    }
  }
  cout << cnt;
  return 0;
}

#include <iostream>
using namespace std;
int dsu[100010];
int fnd(int x) { return (x == dsu[x]) ? x : dsu[x] = fnd(dsu[x]); }
void merge(int u, int v) { dsu[fnd(u)] = fnd(v); }
int main() {
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    dsu[i] = i;
  }
  int x, y, cnt = 0;
  for (int i = 1; i <= m; i++) {
    cin >> x >> y;
    merge(x, y);
  }
  for (int i = 1; i < n; i++) {
    if (fnd(i) != fnd(i + 1)) {
      merge(i, i + 1);
      cnt++;
    }
  }
  cout << cnt;
  return 0;
}


#include <cstdio>
#include <iostream>
using namespace std;
int n, m, fa[1000001], x, y, ans;
int father(int a) {
  if (fa[a] != a)
    fa[a] = father(a);
  return fa[a];
}
int main() {
  scanf("%d%d", &n, &m);
  ans = n - 1;
  for (int i = 1; i <= n; i++)
    fa[i] = i;
  for (int i = 1; i <= m; i++) {
    scanf("%d%d", &x, &y);
    x = father(x);
    y = father(y);
    if (x != y) {
      fa[x] = y;
      ans--;
    }
  }
  printf("%d\\n", ans);
}

#include <cstdio>
#include <iostream>
using namespace std;
int n, m, fa[1000001], x, y, ans;
int father(int a) {
  if (fa[a] != a)
    fa[a] = father(fa[a]);
  return fa[a];
}
int main() {
  scanf("%d%d", &n, &m);
  ans = n - 1;
  for (int i = 1; i <= n; i++)
    fa[i] = i;
  for (int i = 1; i <= m; i++) {
    scanf("%d%d", &x, &y);
    x = father(x);
    y = father(y);
    if (x != y) {
      fa[x] = y;
      ans--;
    }
  }
  printf("%d\\n", ans);
}


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

struct unionfind {
  vi r;

  unionfind(int n) { r = vi(n, -1); }

  int root(int x) {
    if (r.at(x) == -1)
      return x;
    return r.at(x) = root(r.at(x));
  }

  bool unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (r.at(x) > r.at(y))
      swap(x, y);
    r.at(x) += r.at(y);
    r.at(y) = x;
    return true;
  }
};

int main() {
  int n, m, cnt;
  cin >> n >> m;
  cnt = n;
  unionfind uf(n);
  for (int ix = 0; ix < m; ix++) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    if (uf.unite(a, b) == true) {
      cnt--;
    }
  }
  cout << (cnt == 0 ? 0 : cnt - 1) << endl;
}

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

struct unionfind {
  vi r;

  unionfind(int n) { r = vi(n, -1); }

  int root(int x) {
    if (r.at(x) == -1)
      return x;
    return r.at(x) = root(r.at(x));
  }

  bool unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    r.at(y) = x;
    // if(r.at(x)>r.at(y)) swap(x,y);
    // r.at(x) += r.at(y);
    // r.at(y) = x;
    return true;
  }
};

int main() {
  int n, m, cnt;
  cin >> n >> m;
  cnt = n;
  unionfind uf(n);
  for (int ix = 0; ix < m; ix++) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    // uf.unite(a,b);
    if (uf.unite(a, b) == true) {
      cnt--;
    }
  }
  cout << max(0, cnt - 1) << endl;
}


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

#define froop1(a, n) for (int i = a; i < n; i++)
#define froop2(a, n) for (int i = a; i > n; i--)

#define ll long long

#define pq(name, type) priority_queue<type> name
#define vec(name, type, length, value) vector<type> name(length, value)
#define vec2(name, type, length, width, value)                                 \\
  vector<vector<type>> name(length, vector<type>(width, value));

int main() {
  struct UnionFind {
    vector<int> par; // 親の番号

    UnionFind(int N) : par(N) { // 初期化で最初はすべてが根であるとする
      for (int i = 0; i < N; i++)
        par[i] = i;
    }

    int root(int x) { // データxが属する木の根を再帰的に求める
      if (par[x] == x)
        return x;                   // 根を返す
      return par[x] = root(par[x]); // データxの親の番号でroot()を再帰する
    }

    void unite(int x, int y) { // xとyの木を併合
      int rx = root(x);        // xの根
      int ry = root(y);        // yの根
      if (rx == ry)
        return; // 同じ木にある時はそのまま
      par[rx] = ry; // 別々の木にある時は根を同じにしてくっつける
    }

    bool same(int x, int y) { // xとyが同じ木に属するか判別する
      int rx = root(x);
      int ry = root(y);
      return rx == ry;
    }
  };

  int N, M;
  cin >> N >> M;
  UnionFind u(N);
  froop1(0, M) {
    int a, b;
    cin >> a >> b;
    u.unite(a, b);
  }
  int count = 0;
  set<int> m;
  froop1(0, N) {
    int p = u.par[i];
    m.insert(p);
  }
  count = m.size() - 1;

  cout << count << endl;
}

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

#define froop1(a, n) for (int i = a; i < n; i++)
#define froop2(a, n) for (int i = a; i > n; i--)

#define ll long long

#define pq(name, type) priority_queue<type> name
#define vec(name, type, length, value) vector<type> name(length, value)
#define vec2(name, type, length, width, value)                                 \\
  vector<vector<type>> name(length, vector<type>(width, value));

int main() {
  struct UnionFind {
    vector<int> par; // 親の番号

    UnionFind(int N) : par(N) { // 初期化で最初はすべてが根であるとする
      for (int i = 0; i < N; i++)
        par[i] = i;
    }

    int root(int x) { // データxが属する木の根を再帰的に求める
      if (par[x] == x)
        return x;                   // 根を返す
      return par[x] = root(par[x]); // データxの親の番号でroot()を再帰する
    }

    void unite(int x, int y) { // xとyの木を併合
      int rx = root(x);        // xの根
      int ry = root(y);        // yの根
      if (rx == ry)
        return; // 同じ木にある時はそのまま
      par[rx] = ry; // 別々の木にある時は根を同じにしてくっつける
    }

    bool same(int x, int y) { // xとyが同じ木に属するか判別する
      int rx = root(x);
      int ry = root(y);
      return rx == ry;
    }
  };

  int N, M;
  cin >> N >> M;
  UnionFind u(N);
  froop1(0, M) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    u.unite(a, b);
  }
  int count = 0;
  set<int> m;
  froop1(0, N) {
    int p = u.root(i);
    m.insert(p);
  }
  count = m.size() - 1;

  cout << count << endl;
}


/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author Sagor
 */

#include <algorithm>
#include <cmath>
#include <cstring>
#include <deque>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#define gap ' '
#define EPS 1e-9
#define P_INF 2e9 + 17
#define N_INF -2e9 - 17
#define MOD 1000000007
#define PI 2 * acos(0.0)
#define All(x) x.begin(), x.end()
#define Mem(Name, type) memset(Name, type, sizeof(Name))

template <typename T> T GCD(T a, T b) { return a ? GCD(b % a, a) : b; }

template <typename T> T LCM(T a, T b) { return (a * b) / GCD(a, b); }

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
  for (auto ob : v)
    os << ob << " ";
  return os;
}

template <typename T, typename S>
std::ostream &operator<<(std::ostream &os, const std::map<T, S> &v) {
  for (auto ob : v)
    os << ob.first << " : " << ob.second << std::endl;
  return os;
}

using ld = double;
using ll = long long int;
using ul = unsigned long long int;
using namespace std;

class CConnectCities {
  vector<bool> visited;
  vector<vector<int>> G;

  void DFS(int cur, int par) {
    if (!visited[cur])
      visited[cur] = true;
    for (int x : G[cur]) {
      if (x == par)
        continue;
      DFS(x, cur);
    }
  }

public:
  void solve(std::istream &in, std::ostream &out) {
    int n, m;
    in >> n >> m;
    G.resize(n);
    visited.resize(n);
    for (int i = 0; i < m; ++i) {
      int x, y;
      in >> x >> y;
      x--, y--;
      G[x].push_back(y);
      G[y].push_back(x);
    }
    int ans = 0;
    for (int i = 0; i < n; ++i) {
      if (!visited[i]) {
        DFS(0, -1);
        if (i != 0)
          ans++;
      }
    }
    out << ans << endl;
  }
};

int main() {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr);
  CConnectCities solver;
  std::istream &in(std::cin);
  std::ostream &out(std::cout);
  solver.solve(in, out);
  return 0;
}

/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author Sagor
 */

#include <algorithm>
#include <cmath>
#include <cstring>
#include <deque>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#define gap ' '
#define EPS 1e-9
#define P_INF 2e9 + 17
#define N_INF -2e9 - 17
#define MOD 1000000007
#define PI 2 * acos(0.0)
#define All(x) x.begin(), x.end()
#define Mem(Name, type) memset(Name, type, sizeof(Name))

template <typename T> T GCD(T a, T b) { return a ? GCD(b % a, a) : b; }

template <typename T> T LCM(T a, T b) { return (a * b) / GCD(a, b); }

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
  for (auto ob : v)
    os << ob << " ";
  return os;
}

template <typename T, typename S>
std::ostream &operator<<(std::ostream &os, const std::map<T, S> &v) {
  for (auto ob : v)
    os << ob.first << " : " << ob.second << std::endl;
  return os;
}

using ld = double;
using ll = long long int;
using ul = unsigned long long int;
using namespace std;

class CConnectCities {
  vector<bool> visited;
  vector<vector<int>> G;

  void DFS(int cur, int par) {
    if (!visited[cur])
      visited[cur] = true;
    else
      return;
    for (int x : G[cur]) {
      if (x == par)
        continue;
      DFS(x, cur);
    }
  }

public:
  void solve(std::istream &in, std::ostream &out) {
    int n, m;
    in >> n >> m;
    G.resize(n);
    visited.resize(n);
    for (int i = 0; i < m; ++i) {
      int x, y;
      in >> x >> y;
      x--, y--;
      G[x].push_back(y);
      G[y].push_back(x);
    }
    int ans = 0;
    for (int i = 0; i < n; ++i) {
      if (!visited[i]) {
        DFS(i, -1);
        ans++;
      }
    }
    out << ans - 1 << endl;
  }
};

int main() {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr);
  CConnectCities solver;
  std::istream &in(std::cin);
  std::ostream &out(std::cout);
  solver.solve(in, out);
  return 0;
}


#include <bits/stdc++.h>

using namespace std;

template <typename T> void drop(const T &x) {
  cout << x << '\\n';
  exit(0);
}

int n, m;
vector<vector<int>> road;
vector<bool> seen;

void dfs(int c) {
  seen[c] = true;
  for (auto nc : road[c]) {
    if (seen[nc])
      continue;
    dfs(nc);
  }
}

void milkshake() {
  cin >> n >> m;
  road.resize(n);
  for (int i = 0; i < m; i++) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    road[a].emplace_back(b);
    road[b].emplace_back(a);
  }
  bool ok = false;
  int ans = 0;
  while (!ok) {
    seen.assign(n, false);
    dfs(0);
    for (int i = 0; i < n; i++) {
      if (!seen[i]) {
        road[0].emplace_back(i);
        ans++;
        ok = false;
        break;
      }
      ok = true;
    }
  }
  cout << ans << '\\n';
}

signed main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int tt = 1;
  // cin >> tt;
  while (tt--)
    milkshake();

  return 0;
}

#include <bits/stdc++.h>

using namespace std;

template <typename T> void drop(const T &x) {
  cout << x << '\\n';
  exit(0);
}

struct UnionFind {
  vector<int> d;

  UnionFind(int n) : d(n, -1) {}
  int root(int x) {
    if (d[x] < 0)
      return x;
    return d[x] = root(d[x]);
  }

  bool unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (d[x] > d[y])
      swap(x, y);
    d[x] += d[y];
    d[y] = x;
    return true;
  }

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

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

void milkshake() {
  int n, m;
  cin >> n >> m;
  UnionFind uf(n);
  int ans = n - 1;
  for (int i = 0; i < m; i++) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    if (!uf.same(a, b)) {
      uf.unite(a, b);
      ans--;
    }
  }
  cout << ans << '\\n';
}

signed main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int tt = 1;
  // cin >> tt;
  while (tt--)
    milkshake();

  return 0;
}


#include <bits/stdc++.h>

int main() {
  int N, M;
  std::cin >> N >> M;

  std::vector<int> union_find(N);
  for (int i = 0; i < N; i++) {
    union_find[i] = i;
  }
  int a, b;
  auto find_root = [&union_find](int idx) {
    std::vector<int> inter;
    while (union_find[idx] != idx) {
      inter.emplace_back(idx);
      idx = union_find[idx];
    }
    for (auto i : inter) {
      union_find[i] = idx;
    }
    return idx;
  };

  for (int i = 0; i < M; i++) {
    std::cin >> a >> b;
    int root_a = find_root(a);
    int root_b = find_root(b);
    if (root_a != root_b) {
      union_find[root_a] = root_b;
    }
  }
  int cnt = 0;
  for (int i = 0; i < N; i++) {
    int root = find_root(i);
    if (root == i) {
      cnt++;
    }
  }
  std::cout << cnt - 1 << std::endl;
}

#include <bits/stdc++.h>

int main() {
  int N, M;
  std::cin >> N >> M;

  std::vector<int> union_find(N);
  for (int i = 0; i < N; i++) {
    union_find[i] = i;
  }

  auto find_root = [&union_find](int idx) {
    std::vector<int> inter;
    while (union_find[idx] != idx) {
      inter.emplace_back(idx);
      idx = union_find[idx];
    }
    for (auto i : inter) {
      union_find[i] = idx;
    }
    return idx;
  };

  int a, b;
  for (int i = 0; i < M; i++) {
    std::cin >> a >> b;
    a--;
    b--;
    int root_a = find_root(a);
    int root_b = find_root(b);
    if (root_a != root_b) {
      union_find[root_a] = root_b;
    }
  }
  int cnt = 0;
  for (int i = 0; i < N; i++) {
    int root = find_root(i);
    if (root == i) {
      cnt++;
    }
  }
  std::cout << cnt - 1 << std::endl;
}


#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#define ll long long

struct UnionFind {
  std::vector<int> d;
  UnionFind(int n = 0) : d(n, -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])
      std::swap(x, y);
    d[x] += d[y];
    d[y] = x;
    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 main() {
  int N, M;
  std::cin >> N >> M;
  UnionFind uf(N);
  for (int i = 0; i < M; i++) {
    int x, y;
    x--;
    y--;
    std::cin >> x >> y;
    uf.unite(x, y);
  }

  int ans = 0;
  std::map<int, int> data;
  for (int i = 0; i < N; i++) {
    int tmp = uf.size(i);
    if (data[tmp] == 0 and tmp > 1) {
      ans++;
      data[tmp] = 1;
    }
    if (tmp == 1) {
      ans++;
    }
  }
  std::cout << ans - 1 << std::endl;

  return 0;
}

#include <algorithm>
#include <cassert>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#define ll long long

struct dsu {
public:
  dsu() : _n(0) {}
  dsu(int n) : _n(n), parent_or_size(n, -1) {}

  int merge(int a, int b) {
    assert(0 <= a && a < _n);
    assert(0 <= b && b < _n);
    int x = leader(a), y = leader(b);
    if (x == y)
      return x;
    if (-parent_or_size[x] < -parent_or_size[y])
      std::swap(x, y);
    parent_or_size[x] += parent_or_size[y];
    parent_or_size[y] = x;
    return x;
  }

  bool same(int a, int b) {
    assert(0 <= a && a < _n);
    assert(0 <= b && b < _n);
    return leader(a) == leader(b);
  }

  int leader(int a) {
    assert(0 <= a && a < _n);
    if (parent_or_size[a] < 0)
      return a;
    return parent_or_size[a] = leader(parent_or_size[a]);
  }

  int size(int a) {
    assert(0 <= a && a < _n);
    return -parent_or_size[leader(a)];
  }

  std::vector<std::vector<int>> groups() {
    std::vector<int> leader_buf(_n), group_size(_n);
    for (int i = 0; i < _n; i++) {
      leader_buf[i] = leader(i);
      group_size[leader_buf[i]]++;
    }
    std::vector<std::vector<int>> result(_n);
    for (int i = 0; i < _n; i++) {
      result[i].reserve(group_size[i]);
    }
    for (int i = 0; i < _n; i++) {
      result[leader_buf[i]].push_back(i);
    }
    result.erase(
        std::remove_if(result.begin(), result.end(),
                       [&](const std::vector<int> &v) { return v.empty(); }),
        result.end());
    return result;
  }

private:
  int _n;
  // root node: -1 * component size
  // otherwise: parent
  std::vector<int> parent_or_size;
};

int main() {
  int N, M;
  std::cin >> N >> M;
  dsu d(N);
  for (int i = 0; i < M; i++) {
    int x, y;
    std::cin >> x >> y;
    --x;
    --y;
    d.merge(x, y);
  }
  int cnt = 0;
  for (int i = 0; i < N; i++) {
    if (d.leader(i) == i)
      cnt++;
  }
  std::cout << cnt - 1 << std::endl;
  return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll parent[1000], Rank[1000];

void initialize() {
  for (ll i = 1; i <= 1000; i++) {
    parent[i] = i;
    Rank[i] = 1;
  }
}

ll Find(ll r) {
  if (parent[r] == r)
    return r;

  parent[r] = Find(parent[r]);

  return parent[r];
}
ll component, ans = 0;
void Union(ll x, ll y) {
  ll u = Find(x);

  ll v = Find(y);

  if (u != v) { // cout<<"The are different Component so that the include in the
                // same component";

    component--; // first a sob gula alada component e chilo ar ekhon ekoi
                 // component e ene dichi tai comonent num ek ek kore komachi

    if (Rank[v] > Rank[u]) {
      Rank[v] += Rank[u];
      parent[u] = v;
    } // zetar child beshi setar sathe new child add korchi abong mot child num
      // add korchi

    else {
      Rank[u] += Rank[v];
      parent[v] = u;
    }

    // ll mx=max(Rank[u],Rank[v]);

    // ans=max(ans,mx);

    //  cout<<"u ="<<Rank[u]<<endl;

    // cout<<"v= "<<Rank[v]<<endl;

    // ekoi componet e rakhlam

  } else { // cout<<"The are same component";
  }
}

int main() {
  initialize();

  ll N, E, u, v;

  cin >> N;
  cin >> E;
  component = N;
  for (ll i = 1; i <= E; i++) {
    cin >> u >> v;

    Union(u, v);
  }
  cout << component - 1 << endl;
  // cout<<ans<<endl;
}

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll parent[1000000], Rank[1000000];

void initialize() {
  for (ll i = 1; i <= 1000000; i++) {
    parent[i] = i;
    Rank[i] = 1;
  }
}

ll Find(ll r) {
  if (parent[r] == r)
    return r;

  parent[r] = Find(parent[r]);

  return parent[r];
}
ll component, ans = 0;
void Union(ll x, ll y) {
  ll u = Find(x);

  ll v = Find(y);

  if (u != v) { // cout<<"The are different Component so that the include in the
                // same component";

    component--; // first a sob gula alada component e chilo ar ekhon ekoi
                 // component e ene dichi tai comonent num ek ek kore komachi

    if (Rank[v] > Rank[u]) {
      Rank[v] += Rank[u];
      parent[u] = v;
    } // zetar child beshi setar sathe new child add korchi abong mot child num
      // add korchi

    else {
      Rank[u] += Rank[v];
      parent[v] = u;
    }

    // ll mx=max(Rank[u],Rank[v]);

    // ans=max(ans,mx);

    //  cout<<"u ="<<Rank[u]<<endl;

    // cout<<"v= "<<Rank[v]<<endl;

    // ekoi componet e rakhlam

  } else { // cout<<"The are same component";
  }
}

int main() {
  initialize();

  ll N, E, u, v;

  cin >> N;
  cin >> E;
  component = N;
  for (ll i = 1; i <= E; i++) {
    cin >> u >> v;

    Union(u, v);
  }
  cout << component - 1 << endl;
  // cout<<ans<<endl;
}


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

#define rep(i, n) for (ll i = 0; i < n; i++)
class UnionFind {
  vector<int> par;
  vector<int> siz;

public:
  UnionFind(int n) : par(n), siz(n, 1) {
    for (int i = 0; i < n; i++) {
      par[i] = i;
    }
  }
  int root(int x) {
    if (par[x] == x) {
      return x;
    } else {
      return par[x] = root(par[x]);
    }
  }
  bool same(int x, int y) { return root(x) == root(y); }
  bool unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y) {
      return 0;
    }
    if (siz[x] == siz[y]) {
      swap(x, y);
    }
    siz[x] += siz[y];
    par[y] = x;
    return 1;
  }
  int size(int x) { return siz[root(x)]; }
};
int main() {
  int n, q, a, b;
  cin >> n >> q;
  int ans = n - 1;
  UnionFind uf(n);
  rep(i, q) {
    cin >> a >> b;

    if (uf.unite(a, b)) {
      ans--;
    }
  }
  cout << ans << endl;
}

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

#define rep(i, n) for (ll i = 0; i < n; i++)
class UnionFind {
  vector<int> par;
  vector<int> siz;

public:
  UnionFind(int n) : par(n), siz(n, 1) {
    for (int i = 0; i < n; i++) {
      par[i] = i;
    }
  }
  int root(int x) {
    if (par[x] == x) {
      return x;
    } else {
      return par[x] = root(par[x]);
    }
  }
  bool same(int x, int y) { return root(x) == root(y); }
  bool unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y) {
      return 0;
    }
    if (siz[x] == siz[y]) {
      swap(x, y);
    }
    siz[x] += siz[y];
    par[y] = x;
    return 1;
  }
  int size(int x) { return siz[root(x)]; }
};
int main() {
  int n, q, a, b;
  cin >> n >> q;
  int ans = n - 1;
  UnionFind uf(n);
  rep(i, q) {
    cin >> a >> b;
    a--;
    b--;
    if (uf.unite(a, b)) {
      ans--;
    }
  }
  cout << ans << endl;
}


#include <bits/stdc++.h>
#define Mashu cout << "UUZ ate it." << endl
#define RE register int
#define LL int
using namespace std;

inline int read() {
  char ch = getchar();
  int x = 0, cf = 1;
  while (ch < '0' || ch > '9') {
    if (ch == '-')
      cf = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    x = (x << 3) + (x << 1) + (ch ^ 48);
    ch = getchar();
  }
  if (cf < 0)
    return -x;
  else
    return x;
}

LL /*tag[400001], */ num[1200001];

LL lc(LL p) { return p << 1; }

LL rc(LL p) { return p << 1 | 1; }

void pushup(LL p) { num[p] = max(num[lc(p)], num[rc(p)]); }

// void build(LL p, LL l, LL r){
//	if (l == r){
//		num[p] = a[l];
//		return;
//	}
//	LL mid = (l + r) >> 1;
//	build(lc(p), l, mid);
//	build(rc(p), mid + 1, r);
//	pushup(p);
// }

// void upd(LL p, LL l, LL r, LL x){
//	tag[p] += x;
//	num[p] += (r - l + 1) * x;
// }

// void pushdown(LL p, LL l, LL r){
//	LL mid = (l + r) >> 1;
//	upd(lc(p), l, mid, tag[p]);
//	upd(rc(p), mid + 1, r, tag[p]);
//	tag[p] = 0;
// }

void change(LL L, LL R, LL l, LL r, LL p, LL x) {
  if (L <= l && r <= R) {
    //		tag[p] += x;
    //		num[p] += (r - l + 1) * x;
    num[p] = x;
    return;
  }
  //	pushdown(p, l, r);
  LL mid = (l + r) >> 1;
  if (L <= mid)
    change(L, R, l, mid, lc(p), x);
  if (R >= mid + 1)
    change(L, R, mid + 1, r, rc(p), x);
  pushup(p);
}

LL Q(LL L, LL R, LL l, LL r, LL p) {
  if (L <= l && r <= R) {
    return num[p];
  }
  LL ans = -1;
  //	pushdown(p, l, r);
  LL mid = (l + r) >> 1;
  if (L <= mid)
    ans = max(ans, Q(L, R, l, mid, lc(p)));
  if (R >= mid + 1)
    ans = max(ans, Q(L, R, mid + 1, r, rc(p)));
  return ans;
}

int qwq[300010];

int main() {
  int n, k;
  cin >> n >> k;
  for (int i = 1; i <= n; i++) {
    cin >> qwq[i];
  }
  int ans = 1;
  for (int i = 1; i <= n; i++) {
    int l = max(1, qwq[i] - k);
    int r = min(300000, qwq[i] + k);
    int qaq = Q(l, r, 1, 300000, 1) + 1;
    ans = max(ans, qaq);
    change(qwq[i], qwq[i], 1, 300000, 1, qaq);
  }
  cout << ans << endl;
  return 0;
  Mashu;
}

#include <bits/stdc++.h>
#define Mashu cout << "UUZ ate it." << endl
#define RE register int
#define LL int
using namespace std;

inline int read() {
  char ch = getchar();
  int x = 0, cf = 1;
  while (ch < '0' || ch > '9') {
    if (ch == '-')
      cf = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    x = (x << 3) + (x << 1) + (ch ^ 48);
    ch = getchar();
  }
  if (cf < 0)
    return -x;
  else
    return x;
}

LL /*tag[400001], */ num[1200001];

LL lc(LL p) { return p << 1; }

LL rc(LL p) { return p << 1 | 1; }

void pushup(LL p) { num[p] = max(num[lc(p)], num[rc(p)]); }

// void build(LL p, LL l, LL r){
//	if (l == r){
//		num[p] = a[l];
//		return;
//	}
//	LL mid = (l + r) >> 1;
//	build(lc(p), l, mid);
//	build(rc(p), mid + 1, r);
//	pushup(p);
// }

// void upd(LL p, LL l, LL r, LL x){
//	tag[p] += x;
//	num[p] += (r - l + 1) * x;
// }

// void pushdown(LL p, LL l, LL r){
//	LL mid = (l + r) >> 1;
//	upd(lc(p), l, mid, tag[p]);
//	upd(rc(p), mid + 1, r, tag[p]);
//	tag[p] = 0;
// }

void change(LL L, LL R, LL l, LL r, LL p, LL x) {
  if (L <= l && r <= R) {
    //		tag[p] += x;
    //		num[p] += (r - l + 1) * x;
    num[p] = x;
    return;
  }
  //	pushdown(p, l, r);
  LL mid = (l + r) >> 1;
  if (L <= mid)
    change(L, R, l, mid, lc(p), x);
  if (R >= mid + 1)
    change(L, R, mid + 1, r, rc(p), x);
  pushup(p);
}

LL Q(LL L, LL R, LL l, LL r, LL p) {
  if (L <= l && r <= R) {
    return num[p];
  }
  LL ans = -1;
  //	pushdown(p, l, r);
  LL mid = (l + r) >> 1;
  if (L <= mid)
    ans = max(ans, Q(L, R, l, mid, lc(p)));
  if (R >= mid + 1)
    ans = max(ans, Q(L, R, mid + 1, r, rc(p)));
  return ans;
}

int qwq[300010];

int main() {
  int n, k;
  cin >> n >> k;
  for (int i = 1; i <= n; i++) {
    cin >> qwq[i];
  }
  int ans = 1;
  for (int i = 1; i <= n; i++) {
    int l = max(0, qwq[i] - k);
    int r = min(300000, qwq[i] + k);
    int qaq = Q(l, r, 0, 300000, 1) + 1;
    ans = max(ans, qaq);
    change(qwq[i], qwq[i], 0, 300000, 1, qaq);
  }
  cout << ans << endl;
  return 0;
  Mashu;
}


#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define pii pair<int, int>
#define vi vector<int>
#define vii vector<pii>
#define mi map<int, int>
#define mii map<pii, int>
#define endl '\\n'
#define hell 1000000007
#define rep(i, a, b) for (int i = a; i < b; i++)
#define repr(i, a, b) for (int i = a; i >= b; i--)
#define int long long
#define sz(x) (int)x.size()
#define mp make_pair
#define fi first
#define se second
#define io ios_base::sync_with_stdio(false), cin.tie(NULL)
using namespace std;
#define INF 1e7

signed main() {
  io;
  int n, k;
  cin >> n >> k;
  int a[n];
  rep(i, 0, n) cin >> a[i];
  int dp[n];

  dp[0] = 1;
  int ans = 1;
  for (int i = 1; i < n; i++) {
    dp[i] = 1;
    for (int j = 0; j < i; j++) {
      if (abs(a[j] - a[i]) <= k) {
        dp[i] = max(dp[i], 1 + dp[j]);
      }
    }
    ans = max(ans, dp[i]);
  }
  cout << ans << endl;
}

#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define pii pair<int, int>
#define vi vector<int>
#define vii vector<pii>
#define mi map<int, int>
#define mii map<pii, int>
#define endl '\\n'
#define hell 1000000007
#define rep(i, a, b) for (int i = a; i < b; i++)
#define repr(i, a, b) for (int i = a; i >= b; i--)
#define int long long
#define sz(x) (int)x.size()
#define mp make_pair
#define fi first
#define se second
#define io ios_base::sync_with_stdio(false), cin.tie(NULL)
using namespace std;
#define INF 1e9
int tree[1000000];
int n = 300001;
void update(int l, int v) {
  tree[l + n] = v;
  for (int i = l + n; i > 0; i = i >> 1)
    tree[i >> 1] = max(tree[i], tree[i ^ 1]);
}
int query(int l, int r) {
  int res = 0;
  for (l = l + n, r = r + n; l < r; l >>= 1, r >>= 1) {
    if (l & 1)
      res = max(res, tree[l++]);
    if (r & 1)
      res = max(res, tree[--r]);
  }
  return res;
}
signed main() {
  io;
  int s, k;
  cin >> s >> k;
  int a[s];
  rep(i, 0, s) cin >> a[i];

  memset(tree, 0, sizeof(tree));
  for (auto it : a) {
    int c = query(max((ll)0, it - k), min(it + k, (ll)300000) + 1);
    update(it, c + 1);
  }
  cout << query(0, n);
}


#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const ll mod = 998244353;
const int N = 300006;
const ll INF = 1e18;

struct seg_tree {
  vector<int> val;
  int B;
  void init(int n) {
    B = 1;
    while (B < n) {
      B *= 2;
      val.resize(B * 2);
    }
  }

  void upd(int node, int l, int r, int pos, int x) {

    if (l + 1 == r) {
      val[node] = max(val[node], x);
      return;
    }

    if (l > pos || r <= pos)
      return;

    int mid = (l + r) / 2;
    upd(node * 2 + 1, l, mid, pos, x);
    upd(node * 2 + 2, mid, r, pos, x);
    val[node] = max(val[node * 2 + 1], val[node * 2 + 2]);
  }

  void upd(int pos, int x) { upd(0, 0, B, pos, x); }

  int ask(int node, int l, int r, int lf, int rg) {
    if (l >= lf && r <= rg) {
      return val[node];
    }
    if (l >= rg || r <= lf)
      return 0;
    int mid = (l + r) / 2;
    return max(ask(node * 2 + 1, l, mid, lf, rg),
               ask(node * 2 + 2, mid, r, lf, rg));
  }
  int ask(int l, int r) { ask(0, 0, B, l, r); }
};

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

  int n, k;
  cin >> n >> k;
  seg_tree st;
  st.init(N);

  int ans = 0;
  vector<int> dp(N, 0);

  for (int i = 1; i <= n; i++) {
    int x;
    cin >> x;
    int mx = max(st.ask(max(1, x - k), x + 1), st.ask(x, min(N, x + k + 1)));
    dp[i] = mx + 1;
    st.upd(x, dp[i]);
    ans = max(ans, dp[i]);
  }

  cout << ans << '\\n';
  return 0;
}

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const ll mod = 998244353;
const int N = 500006;
const ll INF = 1e18;

struct seg_tree {

  int sz;
  vector<int> val;

  void init(int x) {
    sz = 1;
    while (sz < x)
      sz *= 2;
    val.resize(sz * 2);
  }

  int merge(int a, int b) { return max(a, b); }

  void build(int node, int l, int r, vector<int> &a) {
    if (r - l == 1) {
      if (l < a.size()) {
        val[node] = a[l];
      }
      return;
    }
    int mid = (l + r) / 2;
    build(node * 2 + 1, l, mid, a);
    build(node * 2 + 2, mid, r, a);
    val[node] = merge(val[node * 2 + 1], val[node * 2 + 2]);
  }

  void build(vector<int> &a) { build(0, 0, sz, a); }

  void upd(int node, int l, int r, int pos, ll x) {
    if (r - l == 1) {
      val[node] = x;
      return;
    }
    int mid = (l + r) / 2;
    if (mid > pos)
      upd(node * 2 + 1, l, mid, pos, x);
    if (mid <= pos)
      upd(node * 2 + 2, mid, r, pos, x);
    val[node] = merge(val[node * 2 + 1], val[node * 2 + 2]);
  }
  void upd(int pos, ll x) { upd(0, 0, sz, pos, x); }

  int ask(int node, int l, int r, int st, int dr) {
    if (dr <= l || st >= r)
      return 0;
    if (l >= st && r <= dr)
      return val[node];
    int mid = (l + r) / 2;

    return max(ask(node * 2 + 1, l, mid, st, dr),
               ask(node * 2 + 2, mid, r, st, dr));
  }
  int ask(int st, int dr) { return ask(0, 0, sz, st, dr); }
};

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

  int n, k;
  cin >> n >> k;
  seg_tree st;
  st.init(N);

  int ans = 0;
  vector<int> dp(N, 0);

  for (int i = 1; i <= n; i++) {
    int x;
    cin >> x;
    int mx = max(st.ask(max(0, x - k), x + 1), st.ask(x, min(N, x + k + 1)));
    dp[i] = mx + 1;
    st.upd(x, dp[i]);
    ans = max(ans, dp[i]);
  }

  cout << ans << '\\n';
  return 0;
}

// 1 1 524288
// 5 5 524292
// 4 4 131072
// 3 3 524290
// 8 8 65536
// 6 6 262146
// 9 9 524296
// 7 7 524294
// 2 2 262144
// 4 4 131072


// One Batch Two Batch Penny and Dime

#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ll long long
#define hii cout << "hii" << endl
#define int long long
#define endl '\\n'
#define all(s) s.begin(), s.end()

template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
  for (T i : v)
    os << i << ' ';
  return os;
}
template <class T> ostream &operator<<(ostream &os, const set<T> &v) {
  for (T i : v)
    os << i << ' ';
  return os;
}
template <class T, class S>
ostream &operator<<(ostream &os, const pair<T, S> &v) {
  os << v.first << ' ' << v.second;
  return os;
}
template <class T, class S>
ostream &operator<<(ostream &os, const unordered_map<T, S> &v) {
  for (auto i : v)
    os << '(' << i.first << "=>" << i.second << ')' << ' ';
  return os;
}

#ifndef ONLINE_JUDGE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <class Arg1> void __f(const char *name, Arg1 &&arg1) {
  cerr << name << " : " << arg1 << endl;
}
template <class Arg1, class... Args>
void __f(const char *names, Arg1 &&arg1, Args &&...args) {
  const char *sep = strchr(names + 1, ',');
  cerr.write(names, sep - names) << " : " << arg1 << "  ";
  __f(sep + 1, args...);
}
#else
#define trace(...) 0
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#pragma GCC target(                                                            \\
    "avx2,sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#define _CRT_SECURE_NO_WARNINGS
#endif // ifndef ONLINE_JUDGE

const int N = 1e5 + 5;
const int MAXN = 1e6 + 5;
const int M = 1e6 + 5;
const int mod = 998244353;
const int MOD = 998244353;
const int INF = 1e18 + 8;
const int LG = 21;

int arr[N];

class segtree {
public:
  vector<int> v;
  int N;

  segtree(int n) {
    v.assign(4 * n + 5, 0);
    N = n;
  }

  void buildtree(int s, int e, int treenode) {
    if (s == e) {
      v[treenode] = 0;
      return;
    }
    int mid = s + e >> 1;
    buildtree(s, mid, 2 * treenode + 1);
    buildtree(mid + 1, e, 2 * treenode + 2);
    v[treenode] = max(v[2 * treenode + 1], v[2 * treenode + 2]);
  }

  void updatetree(int idx, int val, int s, int e, int treenode) {
    if (s == e) {
      v[treenode] = val;
      return;
    }
    int mid = s + e >> 1;
    if (idx <= mid)
      updatetree(idx, val, s, mid, 2 * treenode + 1);
    else
      updatetree(idx, val, mid + 1, e, 2 * treenode + 2);
    v[treenode] = max(v[2 * treenode + 1], v[2 * treenode + 2]);
  }

  int querytree(int l, int r, int s, int e, int treenode) {
    if (s >= l and e <= r) {
      return v[treenode];
    }
    if (s > r or l > e)
      return 0;
    int mid = s + e >> 1;
    int left = querytree(l, r, s, mid, 2 * treenode + 1);
    int right = querytree(l, r, mid + 1, e, 2 * treenode + 2);
    return max(left, right);
  }

  void update(int idx, int val) { updatetree(idx, val, 0, N - 1, 0); }

  int query(int l, int r) {
    if (l > r)
      return 0;
    return querytree(l, r, 0, N - 1, 0);
  }

  void build() { buildtree(0, N - 1, 0); }
};

void solve() {
  int n, k;
  cin >> n >> k;
  for (int i = 0; i < n; i++) {
    cin >> arr[i];
  }
  int ret = 0;
  segtree stree(300005);
  for (int i = 0; i < n; i++) {
    int l = max(0LL, arr[i] - k);
    int r = min(arr[i] + k, 300000LL);
    int temp = 1 + stree.query(l, r);
    ret = max(ret, temp);
    stree.update(arr[i], temp);
  }
  cout << ret << endl;
}

int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  int t = 1;
  // cin >> t;
  while (t--)
    solve();
  return 0;
}

// One Batch Two Batch Penny and Dime

#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ll long long
#define hii cout << "hii" << endl
#define int long long
#define endl '\\n'
#define all(s) s.begin(), s.end()

template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
  for (T i : v)
    os << i << ' ';
  return os;
}
template <class T> ostream &operator<<(ostream &os, const set<T> &v) {
  for (T i : v)
    os << i << ' ';
  return os;
}
template <class T, class S>
ostream &operator<<(ostream &os, const pair<T, S> &v) {
  os << v.first << ' ' << v.second;
  return os;
}
template <class T, class S>
ostream &operator<<(ostream &os, const unordered_map<T, S> &v) {
  for (auto i : v)
    os << '(' << i.first << "=>" << i.second << ')' << ' ';
  return os;
}

#ifndef ONLINE_JUDGE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <class Arg1> void __f(const char *name, Arg1 &&arg1) {
  cerr << name << " : " << arg1 << endl;
}
template <class Arg1, class... Args>
void __f(const char *names, Arg1 &&arg1, Args &&...args) {
  const char *sep = strchr(names + 1, ',');
  cerr.write(names, sep - names) << " : " << arg1 << "  ";
  __f(sep + 1, args...);
}
#else
#define trace(...) 0
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#pragma GCC target(                                                            \\
    "avx2,sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#define _CRT_SECURE_NO_WARNINGS
#endif // ifndef ONLINE_JUDGE

const int N = 5e5 + 5;
const int MAXN = 1e6 + 5;
const int M = 1e6 + 5;
const int mod = 998244353;
const int MOD = 998244353;
const int INF = 1e18 + 8;
const int LG = 21;

int arr[N];

class segtree {
public:
  vector<int> v;
  int N;

  segtree(int n) {
    v.assign(4 * n + 5, 0);
    N = n;
  }

  void buildtree(int s, int e, int treenode) {
    if (s == e) {
      v[treenode] = 0;
      return;
    }
    int mid = s + e >> 1;
    buildtree(s, mid, 2 * treenode + 1);
    buildtree(mid + 1, e, 2 * treenode + 2);
    v[treenode] = max(v[2 * treenode + 1], v[2 * treenode + 2]);
  }

  void updatetree(int idx, int val, int s, int e, int treenode) {
    if (s == e) {
      v[treenode] = val;
      return;
    }
    int mid = s + e >> 1;
    if (idx <= mid)
      updatetree(idx, val, s, mid, 2 * treenode + 1);
    else
      updatetree(idx, val, mid + 1, e, 2 * treenode + 2);
    v[treenode] = max(v[2 * treenode + 1], v[2 * treenode + 2]);
  }

  int querytree(int l, int r, int s, int e, int treenode) {
    if (s >= l and e <= r) {
      return v[treenode];
    }
    if (s > r or l > e)
      return 0;
    int mid = s + e >> 1;
    int left = querytree(l, r, s, mid, 2 * treenode + 1);
    int right = querytree(l, r, mid + 1, e, 2 * treenode + 2);
    return max(left, right);
  }

  void update(int idx, int val) { updatetree(idx, val, 0, N - 1, 0); }

  int query(int l, int r) {
    if (l > r)
      return 0;
    return querytree(l, r, 0, N - 1, 0);
  }

  void build() { buildtree(0, N - 1, 0); }
};

void solve() {
  int n, k;
  cin >> n >> k;
  for (int i = 0; i < n; i++) {
    cin >> arr[i];
  }
  int ret = 0;
  segtree stree(300005);
  for (int i = 0; i < n; i++) {
    int l = max(0LL, arr[i] - k);
    int r = min(arr[i] + k, 300000LL);
    int temp = 1 + stree.query(l, r);
    ret = max(ret, temp);
    stree.update(arr[i], temp);
  }
  cout << ret << endl;
}

int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  int t = 1;
  // cin >> t;
  while (t--)
    solve();
  return 0;
}


#include <bits/stdc++.h>
// #include <set>
// #include <vector>
// #include <ostream>
// #include <atcoder/notall>

using namespace std;
using ll = long long;
using VI = vector<int>;
using VL = vector<ll>;
using VD = vector<double>;
using VS = vector<string>;
using VB = vector<bool>;
using VVB = vector<vector<bool>>;
using VVI = vector<VI>;
using VVL = vector<VL>;
using VVD = vector<VD>;
using PII = std::pair<int, int>;
using VPII = std::vector<std::pair<int, int>>;
using PLL = std::pair<ll, ll>;
using VPLL = std::vector<std::pair<ll, ll>>;
using TI3 = std::tuple<int, int, int>;
using TI4 = std::tuple<int, int, int, int>;
using TL3 = std::tuple<ll, ll, ll>;
using TL4 = std::tuple<ll, ll, ll, ll>;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define repr(i, n) for (int i = (int)(n)-1; i >= 0; i--)
#define rep2(i, s, n) for (int i = (s); i < (int)(n); i++)
#define rep3(i, s, n, d) for (int i = (s); i < (int)(n); i += (d))
#define allpt(v) (v).begin(), (v).end()
#define allpt_c(v) (v).cbegin(), (v).cend()
#define allpt_r(v) (v).rbegin(), (v).rend()
#define allpt_cr(v) (v).crbegin(), (v).crend()

const int mod1 = 1e9 + 7, mod2 = 998244353, mod3 = 1e9 + 9;
const int mod = mod1;
const ll inf = 1e18;

const string wsp = " ";
const string tb = "\\t";
const string rt = "\\n";
const string alphabets = "abcdefghijklmnopqrstuvwxyz";

template <typename T> void show1dvec(const vector<T> &v) {
  if (v.size() == 0)
    return;
  int n = v.size() - 1;
  rep(i, n) cout << v[i] << wsp;
  cout << v[n] << rt;
  return;
}

void show2dvec(const vector<string> &v) {
  int n = v.size();
  rep(i, n) cout << v[i] << rt;
}

template <typename T> void show2dvec(const vector<vector<T>> &v) {
  int n = v.size();
  rep(i, n) show1dvec(v[i]);
}

template <typename T> void range_sort(vector<T> &arr, int l, int r) {
  sort(arr.begin() + l, arr.begin() + r);
}

template <typename T, typename S> void show1dpair(const vector<pair<T, S>> &v) {
  int n = v.size();
  rep(i, n) cout << v[i].first << wsp << v[i].second << rt;
  return;
}

template <typename T, typename S>
void pairzip(const vector<pair<T, S>> &v, vector<T> &t, vector<T> &s) {
  int n = v.size();
  rep(i, n) {
    t.push_back(v[i].first);
    s.push_back(v[i].second);
  }
  return;
}

template <typename T> void maxvec(vector<T> &v) {
  T s = v[0];
  int n = v.size();
  rep(i, n - 1) {
    if (s > v[i + 1]) {
      v[i + 1] = s;
    }
    s = v[i + 1];
  }
}

template <typename T, typename S> bool myfind(T t, S s) {
  return find(t.cbegin(), t.cend(), s) != t.cend();
}

bool check(int y, int x, int h, int w) {
  return 0 <= y && y < h && 0 <= x && x < w;
}

bool iskadomatsu(int a, int b, int c) {
  return (a != b && b != c && c != a) && ((a > b && b < c) || (a < b && b > c));
}

double euc_dist(PII a, PII b) {
  return sqrt(pow(a.first - b.first, 2) + pow(a.second - b.second, 2));
}

VS split(string s, char c) {
  VS ret;
  string part;
  s += c;
  rep(i, s.length()) {
    if (s[i] == c) {
      if (part != "")
        ret.emplace_back(part);
      part = "";
    } else if (s[i] != c) {
      part += s[i];
    }
  }
  return ret;
}

template <typename T, typename S, typename R>
ll pow_mod(T p, S q, R mod = 1ll) {
  ll ret = 1, r = p;
  while (q) {
    if (q % 2)
      ret *= r, ret %= mod;
    r = (r * r) % mod, q /= 2;
  }
  return ret % mod;
}

template <typename T, typename S> ll pow_no_mod(T p, S q) {
  ll ret = 1, r = p;
  while (q) {
    if (q % 2)
      ret *= r;
    r = (r * r), q /= 2;
  }
  return ret;
}

void make_frac_tables(VL &frac_list, VL &frac_inv_list) {
  rep(i, frac_list.size() - 1) {
    frac_list[i + 1] *= frac_list[i] * (i + 1);
    frac_list[i + 1] %= mod;
    frac_inv_list[i + 1] *= frac_inv_list[i] * pow_mod(i + 1, mod - 2, mod);
    frac_inv_list[i + 1] %= mod;
  }
}

pair<VL, VL> make_frac_tables(int n) {
  VL frac_list(n + 1, 1), frac_inv_list(n + 1, 1);
  rep(i, n) {
    frac_list[i + 1] *= frac_list[i] * (i + 1);
    frac_list[i + 1] %= mod;
    frac_inv_list[i + 1] *= frac_inv_list[i] * pow_mod(i + 1, mod - 2, mod);
    frac_inv_list[i + 1] %= mod;
  }
  return make_pair(frac_list, frac_inv_list);
}

ll comb(int a, int b, const VL &frac_list, const VL &frac_inv_list) {
  if (a < b)
    return 0;
  if (b < 0)
    return 0;
  ll ret = frac_list[a];
  ret *= frac_inv_list[b];
  ret %= mod;
  ret *= frac_inv_list[a - b];
  ret %= mod;
  return ret;
}

struct vec2d {
  ll x;
  ll y;
  vec2d(ll _x, ll _y) {
    x = _x;
    y = _y;
  }
  ll dot(vec2d p) { return x * p.x + y * p.y; }
  vec2d diff(vec2d p) { return vec2d(x - p.x, y - p.y); }
};

// void djkstra(int n, vector<vec2d> point_list, const VVL cost_list,
//              const VVI &connect) {
//     const ll llm = 1e18;
//     VVL min_cost(n, VL(n, llm));
//     min_cost[0][0] = 0;

//     vector<PII> search = {make_pair(0, 0)};
//     vector<PII> new_search;
//     while (!search.empty()) {
//         for (auto [p, q] : search) {
//             for (auto r : connect[p]) {
//                 if (point_list[r]
//                             .diff(point_list[p])
//                             .dot(point_list[q].diff(point_list[p])) <= 0 &&
//                     min_cost[r][p] > cost_list[r][p] + min_cost[p][q]) {
//                     min_cost[r][p] = cost_list[r][p] + min_cost[p][q];
//                     new_search.emplace_back(make_pair(r, p));
//                 }
//             }
//         }
//         search.clear();
//         search = new_search;
//         new_search.clear();
//         // show1dvec(search);
//         // show1dvec(shortest);
//     }
//     auto ans = *min_element(allpt_c(min_cost[1]));
//     cout << ((ans == llm) ? -1 : ans) << rt;
//     // show2dvec(min_cost);
// }

struct node {
  int parent = -1;
  ll weight = 0;
  int depth = 0;
  int subtree = 0;
  VPII children;
  VPII connect;
  node(int n) {
    parent = -1;
    weight = 0;
    depth = 0;
    subtree = 0;
    children;
    connect;
  }
};

struct graph {
  int _n;
  int root = 0;
  vector<node> nodes;
  graph(int n) {
    _n = n;
    rep(i, _n) nodes.emplace_back(node(_n));
  }
  void getconnect1() {
    int a, b;
    cin >> a >> b;
    a--, b--;
    nodes[a].connect.emplace_back(b, 0);
    nodes[b].connect.emplace_back(a, 0);
  }
  void getconnect2() {
    int a, b, c;
    cin >> a >> b >> c;
    a--, b--;
    nodes[a].connect.emplace_back(b, c);
    nodes[b].connect.emplace_back(a, c);
  }
  void showparent() {
    rep(i, _n - 1) cout << nodes[i].parent << wsp;
    cout << nodes[_n - 1].parent << rt;
  }
  void showweight() {
    rep(i, _n - 1) cout << nodes[i].weight << wsp;
    cout << nodes[_n - 1].weight << rt;
  }
  void showsubtree() {
    rep(i, _n - 1) cout << nodes[i].subtree << wsp;
    cout << nodes[_n - 1].subtree << rt;
  }
  void showdepth() {
    rep(i, _n - 1) cout << nodes[i].depth << wsp;
    cout << nodes[_n - 1].depth << rt;
  }
};

struct point {
  int x;
  int y;
  point() {
    x = 0;
    y = 0;
  }
  point(int _x, int _y) {
    x = _x;
    y = _y;
  }
  void pointinput() {
    int _x, _y;
    cin >> _x >> _y;
    x = _x;
    y = _y;
  }
  void pointinv() { swap(x, y); }
};

double pointseuc(point a, point b) {
  return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}

double dist_segment_point(TL3 segment, point p) {
  double a = get<0>(segment);
  double b = get<1>(segment);
  double c = get<2>(segment);
  return abs(a * p.x + b * p.y - c) / (a * a + b * b + c * c);
}

TL3 segment_parameter(point p, point q) {
  ll a, b, c;
  a = q.y - p.y;
  b = p.x - q.x;
  c = a * p.x + b * p.y;
  TL3 ret = (TL3){a, b, c};
  // cout << a << b << c << rt;
  return ret;
}

int cross_check(TL3 segment, point p) {
  ll a = get<0>(segment);
  ll b = get<1>(segment);
  ll c = get<2>(segment);

  auto f = a * p.x + b * p.y - c;
  int ret;
  if (f > 0)
    ret = 1;
  if (f == 0)
    ret = 0;
  if (f < 0)
    ret = -1;
  return ret;
}

template <typename T>
class RangeMinorMaxorSumQuery // 0-index
{
  int const intmax = 1147483647;
  int const intmin = 0;
  vector<T> sgt;
  int n;
  int k;

public:
  RangeMinorMaxorSumQuery(int n1, int f = -1) {
    if (f == -1)
      f = -1;
    else if (f == 0)
      f = intmin;
    int na = 1;
    int ka = 0;
    while (na < n1) {
      na *= 2;
      ka++;
    }
    for (int i = 0; i < 2 * na; i++)
      sgt.push_back(f);
    n = na;
    k = ka;
  }

  void update_min(int i, int x) {
    i += n;
    sgt[i] = x;
    while (i > 1) {
      i /= 2;
      sgt[i] = min(sgt[2 * i], sgt[2 * i + 1]);
    }
  }
  void update_max(int i, T x) {
    i += n;
    sgt[i] = x;
    while (i > 1) {
      i /= 2;
      sgt[i] = max(sgt[2 * i], sgt[2 * i + 1]);
    }
  }
  void update_sum(int i, T x) {
    i += n;
    sgt[i] = x;
    while (i > 1) {
      i /= 2;
      sgt[i] = sgt[2 * i] + sgt[2 * i + 1];
    }
  }

  void add_sum(int i, T x) {
    i += n;
    sgt[i] += x;
    while (i > 1) {
      i /= 2;
      sgt[i] = sgt[2 * i] + sgt[2 * i + 1];
    }
  }

  T getmin(int a, int b, int k = 1, int l = 0,
           int r = -1) // 閉区間 l <= x < r とする
  {
    if (r == -1)
      r = n;
    if (r <= a || b <= l)
      return intmax;
    if (a == l && b == r)
      return sgt[k];
    else
      return min(getmin(a, min(b, (l + r) / 2), 2 * k, l, (l + r) / 2),
                 getmin(max(a, (l + r) / 2), b, 2 * k + 1, (l + r) / 2, r));
  }
  T getmax(int a, int b, int k = 1, int l = 0,
           int r = -1) // 閉区間 l <= x < r とする
  {
    if (r == -1)
      r = n;
    if (r <= a || b <= l)
      return intmin;
    if (a == l && b == r)
      return sgt[k];
    else
      return max(getmax(a, min(b, (l + r) / 2), 2 * k, l, (l + r) / 2),
                 getmax(max(a, (l + r) / 2), b, 2 * k + 1, (l + r) / 2, r));
  }
  T getsum(int a, int b, int k = 1, int l = 0,
           int r = -1) // 閉区間 l <= x < r とする
  {
    if (r == -1)
      r = n;
    if (r <= a || b <= l)
      return intmin;
    if (a == l && b == r)
      return sgt[k];
    else
      return getsum(a, min(b, (l + r) / 2), 2 * k, l, (l + r) / 2) +
             getsum(max(a, (l + r) / 2), b, 2 * k + 1, (l + r) / 2, r);
  }

  T operator[](int i) { return sgt[i + n]; }

  void printsegtree() {
    for (int i = 0; i < 2 * n; i++) {
      cout << sgt[i] << " ";
    }
    cout << endl;
  }
};

class Unionfind {
  vector<int> p;

public:
  int find(int x);
  void unite(int x, int y);
  bool isunion(int x, int y);
  Unionfind(int n);
  void showtree();
};

Unionfind::Unionfind(int n) {
  for (int i = 0; i < n; i++) {
    p.push_back(i);
  }
}
int Unionfind::find(int x) {
  while (p[x] != x) {
    p[x] = p[p[x]];
    x = p[x];
  }
  return x;
}

void Unionfind::unite(int x, int y) {
  x = Unionfind::find(x);
  y = Unionfind::find(y);
  if (x != y) {
    p[x] = y;
  }
}

bool Unionfind::isunion(int x, int y) {
  return Unionfind::find(x) == Unionfind::find(y);
}

void Unionfind::showtree() {
  for (int i = 0; i < p.size() - 1; i++) {
    cout << p[i] << " ";
  }
  cout << p[p.size() - 1] << "\\n";
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  // リアクティブ問題のときはコメントアウト

#ifdef DEBUG
  cout << "DEBUG MODE" << endl;
  ifstream in("input.txt"); // for debug
  cin.rdbuf(in.rdbuf());    // for debug
#endif

  int n, k, a, b;
  const int m = 400000;
  cin >> n >> k;
  RangeMinorMaxorSumQuery<int> sgt(m, 0);
  rep(i, n) {
    cin >> a;
    b = sgt.getmax(max(0, a - k), a + k + 1);
    sgt.update_max(a, b + 1);
  }
  cout << sgt.getmax(0, m) << rt;
  return 0;
}

#include <bits/stdc++.h>
// #include <set>
// #include <vector>
// #include <ostream>
// #include <atcoder/notall>

using namespace std;
using ll = long long;
using VI = vector<int>;
using VL = vector<ll>;
using VD = vector<double>;
using VS = vector<string>;
using VB = vector<bool>;
using VVB = vector<vector<bool>>;
using VVI = vector<VI>;
using VVL = vector<VL>;
using VVD = vector<VD>;
using PII = std::pair<int, int>;
using VPII = std::vector<std::pair<int, int>>;
using PLL = std::pair<ll, ll>;
using VPLL = std::vector<std::pair<ll, ll>>;
using TI3 = std::tuple<int, int, int>;
using TI4 = std::tuple<int, int, int, int>;
using TL3 = std::tuple<ll, ll, ll>;
using TL4 = std::tuple<ll, ll, ll, ll>;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define repr(i, n) for (int i = (int)(n)-1; i >= 0; i--)
#define rep2(i, s, n) for (int i = (s); i < (int)(n); i++)
#define rep3(i, s, n, d) for (int i = (s); i < (int)(n); i += (d))
#define allpt(v) (v).begin(), (v).end()
#define allpt_c(v) (v).cbegin(), (v).cend()
#define allpt_r(v) (v).rbegin(), (v).rend()
#define allpt_cr(v) (v).crbegin(), (v).crend()

const int mod1 = 1e9 + 7, mod2 = 998244353, mod3 = 1e9 + 9;
const int mod = mod1;
const ll inf = 1e18;

const string wsp = " ";
const string tb = "\\t";
const string rt = "\\n";
const string alphabets = "abcdefghijklmnopqrstuvwxyz";

template <typename T> void show1dvec(const vector<T> &v) {
  if (v.size() == 0)
    return;
  int n = v.size() - 1;
  rep(i, n) cout << v[i] << wsp;
  cout << v[n] << rt;
  return;
}

void show2dvec(const vector<string> &v) {
  int n = v.size();
  rep(i, n) cout << v[i] << rt;
}

template <typename T> void show2dvec(const vector<vector<T>> &v) {
  int n = v.size();
  rep(i, n) show1dvec(v[i]);
}

template <typename T> void range_sort(vector<T> &arr, int l, int r) {
  sort(arr.begin() + l, arr.begin() + r);
}

template <typename T, typename S> void show1dpair(const vector<pair<T, S>> &v) {
  int n = v.size();
  rep(i, n) cout << v[i].first << wsp << v[i].second << rt;
  return;
}

template <typename T, typename S>
void pairzip(const vector<pair<T, S>> &v, vector<T> &t, vector<T> &s) {
  int n = v.size();
  rep(i, n) {
    t.push_back(v[i].first);
    s.push_back(v[i].second);
  }
  return;
}

template <typename T> void maxvec(vector<T> &v) {
  T s = v[0];
  int n = v.size();
  rep(i, n - 1) {
    if (s > v[i + 1]) {
      v[i + 1] = s;
    }
    s = v[i + 1];
  }
}

template <typename T, typename S> bool myfind(T t, S s) {
  return find(t.cbegin(), t.cend(), s) != t.cend();
}

bool check(int y, int x, int h, int w) {
  return 0 <= y && y < h && 0 <= x && x < w;
}

bool iskadomatsu(int a, int b, int c) {
  return (a != b && b != c && c != a) && ((a > b && b < c) || (a < b && b > c));
}

double euc_dist(PII a, PII b) {
  return sqrt(pow(a.first - b.first, 2) + pow(a.second - b.second, 2));
}

VS split(string s, char c) {
  VS ret;
  string part;
  s += c;
  rep(i, s.length()) {
    if (s[i] == c) {
      if (part != "")
        ret.emplace_back(part);
      part = "";
    } else if (s[i] != c) {
      part += s[i];
    }
  }
  return ret;
}

template <typename T, typename S, typename R>
ll pow_mod(T p, S q, R mod = 1ll) {
  ll ret = 1, r = p;
  while (q) {
    if (q % 2)
      ret *= r, ret %= mod;
    r = (r * r) % mod, q /= 2;
  }
  return ret % mod;
}

template <typename T, typename S> ll pow_no_mod(T p, S q) {
  ll ret = 1, r = p;
  while (q) {
    if (q % 2)
      ret *= r;
    r = (r * r), q /= 2;
  }
  return ret;
}

void make_frac_tables(VL &frac_list, VL &frac_inv_list) {
  rep(i, frac_list.size() - 1) {
    frac_list[i + 1] *= frac_list[i] * (i + 1);
    frac_list[i + 1] %= mod;
    frac_inv_list[i + 1] *= frac_inv_list[i] * pow_mod(i + 1, mod - 2, mod);
    frac_inv_list[i + 1] %= mod;
  }
}

pair<VL, VL> make_frac_tables(int n) {
  VL frac_list(n + 1, 1), frac_inv_list(n + 1, 1);
  rep(i, n) {
    frac_list[i + 1] *= frac_list[i] * (i + 1);
    frac_list[i + 1] %= mod;
    frac_inv_list[i + 1] *= frac_inv_list[i] * pow_mod(i + 1, mod - 2, mod);
    frac_inv_list[i + 1] %= mod;
  }
  return make_pair(frac_list, frac_inv_list);
}

ll comb(int a, int b, const VL &frac_list, const VL &frac_inv_list) {
  if (a < b)
    return 0;
  if (b < 0)
    return 0;
  ll ret = frac_list[a];
  ret *= frac_inv_list[b];
  ret %= mod;
  ret *= frac_inv_list[a - b];
  ret %= mod;
  return ret;
}

struct vec2d {
  ll x;
  ll y;
  vec2d(ll _x, ll _y) {
    x = _x;
    y = _y;
  }
  ll dot(vec2d p) { return x * p.x + y * p.y; }
  vec2d diff(vec2d p) { return vec2d(x - p.x, y - p.y); }
};

// void djkstra(int n, vector<vec2d> point_list, const VVL cost_list,
//              const VVI &connect) {
//     const ll llm = 1e18;
//     VVL min_cost(n, VL(n, llm));
//     min_cost[0][0] = 0;

//     vector<PII> search = {make_pair(0, 0)};
//     vector<PII> new_search;
//     while (!search.empty()) {
//         for (auto [p, q] : search) {
//             for (auto r : connect[p]) {
//                 if (point_list[r]
//                             .diff(point_list[p])
//                             .dot(point_list[q].diff(point_list[p])) <= 0 &&
//                     min_cost[r][p] > cost_list[r][p] + min_cost[p][q]) {
//                     min_cost[r][p] = cost_list[r][p] + min_cost[p][q];
//                     new_search.emplace_back(make_pair(r, p));
//                 }
//             }
//         }
//         search.clear();
//         search = new_search;
//         new_search.clear();
//         // show1dvec(search);
//         // show1dvec(shortest);
//     }
//     auto ans = *min_element(allpt_c(min_cost[1]));
//     cout << ((ans == llm) ? -1 : ans) << rt;
//     // show2dvec(min_cost);
// }

struct node {
  int parent = -1;
  ll weight = 0;
  int depth = 0;
  int subtree = 0;
  VPII children;
  VPII connect;
  node(int n) {
    parent = -1;
    weight = 0;
    depth = 0;
    subtree = 0;
    children;
    connect;
  }
};

struct graph {
  int _n;
  int root = 0;
  vector<node> nodes;
  graph(int n) {
    _n = n;
    rep(i, _n) nodes.emplace_back(node(_n));
  }
  void getconnect1() {
    int a, b;
    cin >> a >> b;
    a--, b--;
    nodes[a].connect.emplace_back(b, 0);
    nodes[b].connect.emplace_back(a, 0);
  }
  void getconnect2() {
    int a, b, c;
    cin >> a >> b >> c;
    a--, b--;
    nodes[a].connect.emplace_back(b, c);
    nodes[b].connect.emplace_back(a, c);
  }
  void showparent() {
    rep(i, _n - 1) cout << nodes[i].parent << wsp;
    cout << nodes[_n - 1].parent << rt;
  }
  void showweight() {
    rep(i, _n - 1) cout << nodes[i].weight << wsp;
    cout << nodes[_n - 1].weight << rt;
  }
  void showsubtree() {
    rep(i, _n - 1) cout << nodes[i].subtree << wsp;
    cout << nodes[_n - 1].subtree << rt;
  }
  void showdepth() {
    rep(i, _n - 1) cout << nodes[i].depth << wsp;
    cout << nodes[_n - 1].depth << rt;
  }
};

struct point {
  int x;
  int y;
  point() {
    x = 0;
    y = 0;
  }
  point(int _x, int _y) {
    x = _x;
    y = _y;
  }
  void pointinput() {
    int _x, _y;
    cin >> _x >> _y;
    x = _x;
    y = _y;
  }
  void pointinv() { swap(x, y); }
};

double pointseuc(point a, point b) {
  return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}

double dist_segment_point(TL3 segment, point p) {
  double a = get<0>(segment);
  double b = get<1>(segment);
  double c = get<2>(segment);
  return abs(a * p.x + b * p.y - c) / (a * a + b * b + c * c);
}

TL3 segment_parameter(point p, point q) {
  ll a, b, c;
  a = q.y - p.y;
  b = p.x - q.x;
  c = a * p.x + b * p.y;
  TL3 ret = (TL3){a, b, c};
  // cout << a << b << c << rt;
  return ret;
}

int cross_check(TL3 segment, point p) {
  ll a = get<0>(segment);
  ll b = get<1>(segment);
  ll c = get<2>(segment);

  auto f = a * p.x + b * p.y - c;
  int ret;
  if (f > 0)
    ret = 1;
  if (f == 0)
    ret = 0;
  if (f < 0)
    ret = -1;
  return ret;
}

template <typename T>
class RangeMinorMaxorSumQuery // 0-index
{
  int const intmax = 1147483647;
  int const intmin = 0;
  vector<T> sgt;
  int n;
  int k;

public:
  RangeMinorMaxorSumQuery(int n1, int f = -1) {
    if (f == -1)
      f = -1;
    else if (f == 0)
      f = intmin;
    int na = 1;
    int ka = 0;
    while (na < n1) {
      na *= 2;
      ka++;
    }
    for (int i = 0; i < 2 * na; i++)
      sgt.push_back(f);
    n = na;
    k = ka;
  }

  void update_min(int i, int x) {
    i += n;
    sgt[i] = x;
    while (i > 1) {
      i /= 2;
      sgt[i] = min(sgt[2 * i], sgt[2 * i + 1]);
    }
  }
  void update_max(int i, T x) {
    i += n;
    sgt[i] = x;
    while (i > 1) {
      i /= 2;
      sgt[i] = max(sgt[2 * i], sgt[2 * i + 1]);
    }
  }
  void update_sum(int i, T x) {
    i += n;
    sgt[i] = x;
    while (i > 1) {
      i /= 2;
      sgt[i] = sgt[2 * i] + sgt[2 * i + 1];
    }
  }

  void add_sum(int i, T x) {
    i += n;
    sgt[i] += x;
    while (i > 1) {
      i /= 2;
      sgt[i] = sgt[2 * i] + sgt[2 * i + 1];
    }
  }

  T getmin(int a, int b, int k = 1, int l = 0,
           int r = -1) // 閉区間 l <= x < r とする
  {
    if (r == -1)
      r = n;
    if (r <= a || b <= l)
      return intmax;
    if (a == l && b == r)
      return sgt[k];
    else
      return min(getmin(a, min(b, (l + r) / 2), 2 * k, l, (l + r) / 2),
                 getmin(max(a, (l + r) / 2), b, 2 * k + 1, (l + r) / 2, r));
  }
  T getmax(int a, int b, int k = 1, int l = 0,
           int r = -1) // 閉区間 l <= x < r とする
  {
    if (r == -1)
      r = n;
    if (r <= a || b <= l)
      return intmin;
    if (a == l && b == r)
      return sgt[k];
    else
      return max(getmax(a, min(b, (l + r) / 2), 2 * k, l, (l + r) / 2),
                 getmax(max(a, (l + r) / 2), b, 2 * k + 1, (l + r) / 2, r));
  }
  T getsum(int a, int b, int k = 1, int l = 0,
           int r = -1) // 閉区間 l <= x < r とする
  {
    if (r == -1)
      r = n;
    if (r <= a || b <= l)
      return intmin;
    if (a == l && b == r)
      return sgt[k];
    else
      return getsum(a, min(b, (l + r) / 2), 2 * k, l, (l + r) / 2) +
             getsum(max(a, (l + r) / 2), b, 2 * k + 1, (l + r) / 2, r);
  }

  T operator[](int i) { return sgt[i + n]; }

  void printsegtree() {
    for (int i = 0; i < 2 * n; i++) {
      cout << sgt[i] << " ";
    }
    cout << endl;
  }
};

class Unionfind {
  vector<int> p;

public:
  int find(int x);
  void unite(int x, int y);
  bool isunion(int x, int y);
  Unionfind(int n);
  void showtree();
};

Unionfind::Unionfind(int n) {
  for (int i = 0; i < n; i++) {
    p.push_back(i);
  }
}
int Unionfind::find(int x) {
  while (p[x] != x) {
    p[x] = p[p[x]];
    x = p[x];
  }
  return x;
}

void Unionfind::unite(int x, int y) {
  x = Unionfind::find(x);
  y = Unionfind::find(y);
  if (x != y) {
    p[x] = y;
  }
}

bool Unionfind::isunion(int x, int y) {
  return Unionfind::find(x) == Unionfind::find(y);
}

void Unionfind::showtree() {
  for (int i = 0; i < p.size() - 1; i++) {
    cout << p[i] << " ";
  }
  cout << p[p.size() - 1] << "\\n";
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  // リアクティブ問題のときはコメントアウト

#ifdef DEBUG
  cout << "DEBUG MODE" << endl;
  ifstream in("input.txt"); // for debug
  cin.rdbuf(in.rdbuf());    // for debug
#endif

  int n, k, a, b;
  const int m = 400000;
  cin >> n >> k;
  RangeMinorMaxorSumQuery<int> sgt(m, 0);
  rep(i, n) {
    cin >> a;
    b = sgt.getmax(max(0, a - k), min(m, a + k + 1));
    sgt.update_max(a, b + 1);
  }
  cout << sgt.getmax(0, m) << rt;
  return 0;
}


#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <vector>
// #include <numeric> //iota
// #include <sstream>
// #include <cstring>
// #include <tuple>
// #include <random>
// #include <string>
// #include <unordered_set>
// #include <bitset>
// #include <unordered_map>
// #include <stack>
// #include <cmath>
// #include <deque>
// #include <queue>
// #include <list>
#include <array>

using namespace std;
#define all(x) (x).begin(), (x).end()
#define vec vector
#define pb push_back
#define pp pop_back
#define fi first
#define IOS                                                                    \\
  ios::sync_with_stdio(0);                                                     \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define se second
#define un_map unordered_map
#define rep(i, a, n) for (int i = a; i < n; ++i)
#define inc_rep(i, a, n, inc) for (int i = a; i < n; i += inc)
#define couts(x) cout << x << "\\n"
#define watch(x) cout << #x << " : " << x << endl;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLII;
template <typename T> void print(vector<T> &v) {
  rep(i, 0, (int)v.size()) cout << v[i] << " ";
  cout << endl;
}
int nxt() {
  int x;
  cin >> x;
  return x;
}
ll nxtl() {
  ll x;
  cin >> x;
  return x;
}
string nxts() {
  string x;
  cin >> x;
  return x;
}
double nxtd() {
  double x;
  cin >> x;
  return x;
}

void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\\'' << x << '\\''; }
void __print(const char *x) { cerr << '\\"' << x << '\\"'; }
void __print(const string &x) { cerr << '\\"' << x << '\\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }

template <typename T, typename V> void __print(const pair<T, V> &x) {
  cerr << '{';
  __print(x.first);
  cerr << ',';
  __print(x.second);
  cerr << '}';
}
template <typename T> void __print(const T &x) {
  int f = 0;
  cerr << '{';
  for (auto &i : x)
    cerr << (f++ ? "," : ""), __print(i);
  cerr << "}";
}
void _print() { cerr << "]\\n"; }
template <typename T, typename... V> void _print(T t, V... v) {
  __print(t);
  if (sizeof...(v))
    cerr << ", ";
  _print(v...);
}

#ifndef ONLINE_JUDGE
#define debug(x...)                                                            \\
  cerr << "[" << #x << "] = [";                                                \\
  _print(x)
#else
#define debug(x...)
#endif

ll power_mod(ll a, ll b, ll mo) {
  ll ans = 1;
  while (b) {
    if (b & 1) {
      ans = (ans % mo * a % mo) % mo;
    }
    a = (a % mo * a % mo) % mo;
    b /= 2;
  }
  return ans;
}
ll POW(ll a, ll b) {
  ll ans = 1;
  while (b) {
    if (b & 1) {
      ans = ans * a;
    }
    a = a * a;
    b /= 2;
  }
  return ans;
}

// string int_to_string(int x) {
// stringstream ss;
// ss << x;
// string ni = ss.str();
// return ni;
//}

// int string_to_int(string x) {
// int n;
// stringstream s(x);
// s >> n;
// return n;
//}

// char int_to_char(int a) {
// return a + '0';
//}

// void INVERSE() {
// fact[0] = 1;
// for (ll i = 1; i <= z; ++i) {
// fact[i] = (fact[i - 1] * i) % mod;
//}
// inv[0] = 1;
// inv[1] = 1;
// for (ll i = 2; i <= z; ++i) {
// inv[i] = (mod - (mod / i) * inv[mod % i] % mod) % mod;
//}
// mul[0] = 1;
// for (int i = 1; i <= z; ++i) {
// mul[i] = (mul[i - 1] * inv[i]) % mod;
//}
//}

// read questions carefully , write clean code and check your logic again on WA
// !!!

// problems are not difficult just make sure you understand the qusetion and
// just think smartly (make sure to use pen and paper when needed)

// void update(int index, int val) {
// for (; index <= n; index += index & -index) {
// fen[index] = (val + fen[index]) % mod;
//}
//}
// void query(int index) {
// long long sum = 0;
// for (; index > 0; index -= index & -index) {
// sum = (sum + fen[index]) % mod;
//}
// return sum;
//}
int p = 300000 + 1;
int dp[300000 + 2];
int v[300000 + 2];
int segment_tree[300000 + 2];
int n, k;

void build_tree(int l, int r, int index) {
  if (l == r) {
    segment_tree[index] = v[l];
    return;
  }
  int half = (l + r) / 2;
  build_tree(l, half, index * 2);
  build_tree(half + 1, r, index * 2 + 1);
  segment_tree[index] =
      min(segment_tree[index * 2], segment_tree[index * 2 + 1]);
}
void update(int l, int r, int index, int check_index, int val) {
  if (l == r) {
    segment_tree[index] = val;
    return;
  }
  int mid = (l + r) / 2;
  if (check_index <= mid) {
    update(l, mid, index * 2, check_index, val);
  } else {
    update(mid + 1, r, index * 2 + 1, check_index, val);
  }
  segment_tree[index] =
      max(segment_tree[index * 2], segment_tree[index * 2 + 1]);
}
int query(int l, int r, int l1, int r1, int index) {
  if (l1 <= l && r1 >= r) {
    return segment_tree[index];
  }
  if (r1 < l || l1 > r) {
    return 0;
  }
  int mid = (l + r) / 2;
  return max(query(l, mid, l1, r1, index * 2),
             query(mid + 1, r, l1, r1, index * 2 + 1));
}

int main() {
  cin >> n >> k;
  for (int i = 0; i < n; ++i)
    cin >> v[i];
  for (int i = n - 1; i >= 0; --i) {
    int r = (v[i] + k >= p) ? v[i] + k : p;
    int l = (v[i] - k >= 0) ? v[i] - k : 0;
    int val = query(1, n, l, r, 1);
    dp[v[i]] = val + 1;
    update(1, n, 1, v[i], dp[v[i]]);
  }

  int maxm = 0;
  for (int i = 0; i <= 300000; ++i)
    maxm = max(maxm, dp[i]);
  cout << maxm;
}

#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <vector>
// #include <numeric> //iota
// #include <sstream>
// #include <cstring>
// #include <tuple>
// #include <random>
// #include <string>
// #include <unordered_set>
// #include <bitset>
// #include <unordered_map>
// #include <stack>
// #include <cmath>
// #include <deque>
// #include <queue>
// #include <list>
#include <array>

using namespace std;
#define all(x) (x).begin(), (x).end()
#define vec vector
#define pb push_back
#define pp pop_back
#define fi first
#define IOS                                                                    \\
  ios::sync_with_stdio(0);                                                     \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define se second
#define un_map unordered_map
#define rep(i, a, n) for (int i = a; i < n; ++i)
#define inc_rep(i, a, n, inc) for (int i = a; i < n; i += inc)
#define couts(x) cout << x << "\\n"
#define watch(x) cout << #x << " : " << x << endl;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLII;
template <typename T> void print(vector<T> &v) {
  rep(i, 0, (int)v.size()) cout << v[i] << " ";
  cout << endl;
}
int nxt() {
  int x;
  cin >> x;
  return x;
}
ll nxtl() {
  ll x;
  cin >> x;
  return x;
}
string nxts() {
  string x;
  cin >> x;
  return x;
}
double nxtd() {
  double x;
  cin >> x;
  return x;
}

void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\\'' << x << '\\''; }
void __print(const char *x) { cerr << '\\"' << x << '\\"'; }
void __print(const string &x) { cerr << '\\"' << x << '\\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }

template <typename T, typename V> void __print(const pair<T, V> &x) {
  cerr << '{';
  __print(x.first);
  cerr << ',';
  __print(x.second);
  cerr << '}';
}
template <typename T> void __print(const T &x) {
  int f = 0;
  cerr << '{';
  for (auto &i : x)
    cerr << (f++ ? "," : ""), __print(i);
  cerr << "}";
}
void _print() { cerr << "]\\n"; }
template <typename T, typename... V> void _print(T t, V... v) {
  __print(t);
  if (sizeof...(v))
    cerr << ", ";
  _print(v...);
}

#ifndef ONLINE_JUDGE
#define debug(x...)                                                            \\
  cerr << "[" << #x << "] = [";                                                \\
  _print(x)
#else
#define debug(x...)
#endif

ll power_mod(ll a, ll b, ll mo) {
  ll ans = 1;
  while (b) {
    if (b & 1) {
      ans = (ans % mo * a % mo) % mo;
    }
    a = (a % mo * a % mo) % mo;
    b /= 2;
  }
  return ans;
}
ll POW(ll a, ll b) {
  ll ans = 1;
  while (b) {
    if (b & 1) {
      ans = ans * a;
    }
    a = a * a;
    b /= 2;
  }
  return ans;
}

// string int_to_string(int x) {
// stringstream ss;
// ss << x;
// string ni = ss.str();
// return ni;
//}

// int string_to_int(string x) {
// int n;
// stringstream s(x);
// s >> n;
// return n;
//}

// char int_to_char(int a) {
// return a + '0';
//}

// void INVERSE() {
// fact[0] = 1;
// for (ll i = 1; i <= z; ++i) {
// fact[i] = (fact[i - 1] * i) % mod;
//}
// inv[0] = 1;
// inv[1] = 1;
// for (ll i = 2; i <= z; ++i) {
// inv[i] = (mod - (mod / i) * inv[mod % i] % mod) % mod;
//}
// mul[0] = 1;
// for (int i = 1; i <= z; ++i) {
// mul[i] = (mul[i - 1] * inv[i]) % mod;
//}
//}

// read questions carefully , write clean code and check your logic again on WA
// !!!

// problems are not difficult just make sure you understand the qusetion and
// just think smartly (make sure to use pen and paper when needed)

// void update(int index, int val) {
// for (; index <= n; index += index & -index) {
// fen[index] = (val + fen[index]) % mod;
//}
//}
// void query(int index) {
// long long sum = 0;
// for (; index > 0; index -= index & -index) {
// sum = (sum + fen[index]) % mod;
//}
// return sum;
//}
int const p = 800000;
int dp[p];
int v[p];
int segment_tree[p];
int fen[p];
int segme[p];
int n, k;
void SetMax(int pos, int x) {
  for (int i = pos + p; i; i >>= 1)
    fen[i] = max(fen[i], x);
}
int GetMax(int L, int R) {
  int res = 0;
  for (L += p, R += p; L < R; L >>= 1, R >>= 1) {
    if (L & 1) {
      res = max(res, fen[L]);
      L++;
    }
    if (R & 1) {
      R--;
      res = max(res, fen[R]);
    }
  }
  return res;
}

// void build_tree(int l, int r, int index) {
// if (l == r) {
// segment_tree[index] = v[l];
// return ;
//}
// int half = (l + r) / 2;
// build_tree(l,half,index*2);
// build_tree(half + 1,r,index*2 + 1);
// segment_tree[index] = min(segment_tree[index * 2], segment_tree[index * 2 +
// 1]);
//}
// void update(int l, int r, int index, int check_index, int val) {
// if (l == r) {
// segment_tree[index] = val;
// return ;
//}
// int mid = (l + r) / 2;
// if (check_index <= mid) {
// update(l,mid,index * 2,check_index, val);
//}else {
// update(mid + 1,r,index * 2 + 1,check_index, val);
//}
// segment_tree[index] = max(segment_tree[index * 2],segment_tree[index * 2 +
// 1]);

//}
// int query(int l, int r, int l1 , int r1, int index) {
// if (l1 <= l && r1 >= r) {
// return segment_tree[index];
//}
// if (r1 < l || l1 > r) {
// return 0;
//}
// int mid = (l + r) / 2;
// return max(query(l,mid,l1,r1,index*2),query(mid + 1,r,l1,r1,index*2 + 1));
//}

int main() {
  cin >> n >> k;
  for (int i = 1; i <= n; ++i) {
    cin >> v[i];
    v[i]++;
  }
  for (int i = n; i > 0; --i) {
    int r = v[i] + k;
    int l = (v[i] - k >= 1) ? v[i] - k : 1;
    int val = GetMax(l, r + 1);
    dp[v[i]] = val + 1;
    SetMax(v[i], dp[v[i]]);
    // cout << l << " " <<  r << " " << dp[v[i]] << " " << v[i] << " " << val <<
    // " " << dp[val] << endl;
  }

  int maxm = 0;
  for (int i = 0; i <= 300000 + 1; ++i)
    maxm = max(maxm, dp[i]);
  cout << maxm;
}


#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <vector>
// #include <numeric> //iota
// #include <sstream>
// #include <cstring>
// #include <tuple>
// #include <random>
// #include <string>
// #include <unordered_set>
// #include <bitset>
// #include <unordered_map>
// #include <stack>
// #include <cmath>
// #include <deque>
// #include <queue>
// #include <list>
#include <array>

using namespace std;
#define all(x) (x).begin(), (x).end()
#define vec vector
#define pb push_back
#define pp pop_back
#define fi first
#define IOS                                                                    \\
  ios::sync_with_stdio(0);                                                     \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define se second
#define un_map unordered_map
#define rep(i, a, n) for (int i = a; i < n; ++i)
#define inc_rep(i, a, n, inc) for (int i = a; i < n; i += inc)
#define couts(x) cout << x << "\\n"
#define watch(x) cout << #x << " : " << x << endl;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLII;
template <typename T> void print(vector<T> &v) {
  rep(i, 0, (int)v.size()) cout << v[i] << " ";
  cout << endl;
}
int nxt() {
  int x;
  cin >> x;
  return x;
}
ll nxtl() {
  ll x;
  cin >> x;
  return x;
}
string nxts() {
  string x;
  cin >> x;
  return x;
}
double nxtd() {
  double x;
  cin >> x;
  return x;
}

void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\\'' << x << '\\''; }
void __print(const char *x) { cerr << '\\"' << x << '\\"'; }
void __print(const string &x) { cerr << '\\"' << x << '\\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }

template <typename T, typename V> void __print(const pair<T, V> &x) {
  cerr << '{';
  __print(x.first);
  cerr << ',';
  __print(x.second);
  cerr << '}';
}
template <typename T> void __print(const T &x) {
  int f = 0;
  cerr << '{';
  for (auto &i : x)
    cerr << (f++ ? "," : ""), __print(i);
  cerr << "}";
}
void _print() { cerr << "]\\n"; }
template <typename T, typename... V> void _print(T t, V... v) {
  __print(t);
  if (sizeof...(v))
    cerr << ", ";
  _print(v...);
}

#ifndef ONLINE_JUDGE
#define debug(x...)                                                            \\
  cerr << "[" << #x << "] = [";                                                \\
  _print(x)
#else
#define debug(x...)
#endif

ll power_mod(ll a, ll b, ll mo) {
  ll ans = 1;
  while (b) {
    if (b & 1) {
      ans = (ans % mo * a % mo) % mo;
    }
    a = (a % mo * a % mo) % mo;
    b /= 2;
  }
  return ans;
}
ll POW(ll a, ll b) {
  ll ans = 1;
  while (b) {
    if (b & 1) {
      ans = ans * a;
    }
    a = a * a;
    b /= 2;
  }
  return ans;
}

// string int_to_string(int x) {
// stringstream ss;
// ss << x;
// string ni = ss.str();
// return ni;
//}

// int string_to_int(string x) {
// int n;
// stringstream s(x);
// s >> n;
// return n;
//}

// char int_to_char(int a) {
// return a + '0';
//}

// void INVERSE() {
// fact[0] = 1;
// for (ll i = 1; i <= z; ++i) {
// fact[i] = (fact[i - 1] * i) % mod;
//}
// inv[0] = 1;
// inv[1] = 1;
// for (ll i = 2; i <= z; ++i) {
// inv[i] = (mod - (mod / i) * inv[mod % i] % mod) % mod;
//}
// mul[0] = 1;
// for (int i = 1; i <= z; ++i) {
// mul[i] = (mul[i - 1] * inv[i]) % mod;
//}
//}

// read questions carefully , write clean code and check your logic again on WA
// !!!

// problems are not difficult just make sure you understand the qusetion and
// just think smartly (make sure to use pen and paper when needed)

int const p = 300000;
int dp[p + 1];
int v[p + 1];
int segment_tree[2 * p + 2];
int n, k;
int sized = p;
int query(int l_in, int r_in, int index = 1, int l = 1, int r = sized) {
  if (r_in >= r && l_in <= l) {
    return segment_tree[index];
  }
  if (l_in > r || r_in < l) {
    return 0;
  }
  int mid = (l + r) / 2;
  return max(query(l_in, r_in, index * 2, l, mid),
             query(l_in, r_in, index * 2 + 1, mid + 1, r));
}

void update(int index_in, int val, int index = 1, int l = 1, int r = sized) {
  if (l == r) {
    segment_tree[index] = val;
    return;
  }
  int mid = (l + r) / 2;
  if (index_in <= mid) {
    update(index_in, val, index * 2, l, mid);
  } else {
    update(index_in, val, index * 2 + 1, mid + 1, r);
  }
  segment_tree[index] =
      max(segment_tree[index * 2], segment_tree[index * 2 + 1]);
}

int main() {
  cin >> n >> k;
  for (int i = 0; i < n; ++i) {
    cin >> v[i];
    v[i]++;
  }
  for (int i = n - 1; i >= 0; --i) {
    int r = (v[i] + k >= p) ? p : v[i] + k;
    int l = (v[i] - k >= 1) ? v[i] - k : 1;
    int val = query(l, r);
    dp[v[i]] = val + 1;
    update(v[i], dp[v[i]]);
  }
  int maxm = 0;
  for (int i = 0; i <= p; ++i)
    maxm = max(maxm, dp[i]);
  cout << maxm;
}

#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <vector>
// #include <numeric> //iota
// #include <sstream>
// #include <cstring>
// #include <tuple>
// #include <random>
// #include <string>
// #include <unordered_set>
// #include <bitset>
// #include <unordered_map>
// #include <stack>
// #include <cmath>
// #include <deque>
// #include <queue>
// #include <list>
#include <array>

using namespace std;
#define all(x) (x).begin(), (x).end()
#define vec vector
#define pb push_back
#define pp pop_back
#define fi first
#define IOS                                                                    \\
  ios::sync_with_stdio(0);                                                     \\
  cin.tie(0);                                                                  \\
  cout.tie(0);
#define se second
#define un_map unordered_map
#define rep(i, a, n) for (int i = a; i < n; ++i)
#define inc_rep(i, a, n, inc) for (int i = a; i < n; i += inc)
#define couts(x) cout << x << "\\n"
#define watch(x) cout << #x << " : " << x << endl;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLII;
template <typename T> void print(vector<T> &v) {
  rep(i, 0, (int)v.size()) cout << v[i] << " ";
  cout << endl;
}
int nxt() {
  int x;
  cin >> x;
  return x;
}
ll nxtl() {
  ll x;
  cin >> x;
  return x;
}
string nxts() {
  string x;
  cin >> x;
  return x;
}
double nxtd() {
  double x;
  cin >> x;
  return x;
}

void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\\'' << x << '\\''; }
void __print(const char *x) { cerr << '\\"' << x << '\\"'; }
void __print(const string &x) { cerr << '\\"' << x << '\\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }

template <typename T, typename V> void __print(const pair<T, V> &x) {
  cerr << '{';
  __print(x.first);
  cerr << ',';
  __print(x.second);
  cerr << '}';
}
template <typename T> void __print(const T &x) {
  int f = 0;
  cerr << '{';
  for (auto &i : x)
    cerr << (f++ ? "," : ""), __print(i);
  cerr << "}";
}
void _print() { cerr << "]\\n"; }
template <typename T, typename... V> void _print(T t, V... v) {
  __print(t);
  if (sizeof...(v))
    cerr << ", ";
  _print(v...);
}

#ifndef ONLINE_JUDGE
#define debug(x...)                                                            \\
  cerr << "[" << #x << "] = [";                                                \\
  _print(x)
#else
#define debug(x...)
#endif

ll power_mod(ll a, ll b, ll mo) {
  ll ans = 1;
  while (b) {
    if (b & 1) {
      ans = (ans % mo * a % mo) % mo;
    }
    a = (a % mo * a % mo) % mo;
    b /= 2;
  }
  return ans;
}
ll POW(ll a, ll b) {
  ll ans = 1;
  while (b) {
    if (b & 1) {
      ans = ans * a;
    }
    a = a * a;
    b /= 2;
  }
  return ans;
}

// string int_to_string(int x) {
// stringstream ss;
// ss << x;
// string ni = ss.str();
// return ni;
//}

// int string_to_int(string x) {
// int n;
// stringstream s(x);
// s >> n;
// return n;
//}

// char int_to_char(int a) {
// return a + '0';
//}

// void INVERSE() {
// fact[0] = 1;
// for (ll i = 1; i <= z; ++i) {
// fact[i] = (fact[i - 1] * i) % mod;
//}
// inv[0] = 1;
// inv[1] = 1;
// for (ll i = 2; i <= z; ++i) {
// inv[i] = (mod - (mod / i) * inv[mod % i] % mod) % mod;
//}
// mul[0] = 1;
// for (int i = 1; i <= z; ++i) {
// mul[i] = (mul[i - 1] * inv[i]) % mod;
//}
//}

// read questions carefully , write clean code and check your logic again on WA
// !!!

// problems are not difficult just make sure you understand the qusetion and
// just think smartly (make sure to use pen and paper when needed)

int const p = 300000;
int dp[p + 1];
int v[p + 1];
int segment_tree[4 * p + 2];
int n, k;
int sized = p;
int query(int l_in, int r_in, int index = 1, int l = 1, int r = sized) {
  if (r_in >= r && l_in <= l) {
    return segment_tree[index];
  }
  if (l_in > r || r_in < l) {
    return 0;
  }
  int mid = (l + r) / 2;
  return max(query(l_in, r_in, index * 2, l, mid),
             query(l_in, r_in, index * 2 + 1, mid + 1, r));
}

void update(int index_in, int val, int index = 1, int l = 1, int r = sized) {
  if (l == r) {
    segment_tree[index] = val;
    return;
  }
  int mid = (l + r) / 2;
  if (index_in <= mid) {
    update(index_in, val, index * 2, l, mid);
  } else {
    update(index_in, val, index * 2 + 1, mid + 1, r);
  }
  segment_tree[index] =
      max(segment_tree[index * 2], segment_tree[index * 2 + 1]);
}

int main() {
  cin >> n >> k;
  for (int i = 0; i < n; ++i) {
    cin >> v[i];
    v[i]++;
  }
  for (int i = n - 1; i >= 0; --i) {
    int r = (v[i] + k >= p) ? p : v[i] + k;
    int l = (v[i] - k >= 1) ? v[i] - k : 1;
    int val = query(l, r);
    dp[v[i]] = val + 1;
    update(v[i], dp[v[i]]);
  }
  int maxm = 0;
  for (int i = 0; i <= p; ++i)
    maxm = max(maxm, dp[i]);
  cout << maxm;
}