#include <bits/stdc++.h>
using namespace std;
inline int read() {
  int w = 1, s = 0;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') w = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    s = s * 10 + ch - '0';
    ch = getchar();
  }
  return w * s;
}
struct LCT {
  int ch[200010][2], fa[200010], rev[200100], Sta[200010];
  inline int getf(int x) { return ch[fa[x]][1] == x; }
  inline int isroot(int x) { return ch[fa[x]][0] != x && ch[fa[x]][1] != x; }
  inline void Push(int x) {
    rev[x] ^= 1;
    swap(ch[x][0], ch[x][1]);
  }
  inline void Pushdown(int x) {
    if (rev[x]) {
      if (ch[x][1]) Push(ch[x][1]);
      if (ch[x][0]) Push(ch[x][0]);
      rev[x] = 0;
    }
  }
  inline void Rotate(int x) {
    int old = fa[x], oldf = fa[old], whichx = getf(x);
    ch[old][whichx] = ch[x][whichx ^ 1];
    fa[ch[old][whichx]] = old;
    if (!isroot(old)) ch[oldf][getf(old)] = x;
    fa[x] = oldf;
    ch[x][whichx ^ 1] = old;
    fa[old] = x;
  }
  inline void Splay(int x) {
    int top = 0;
    Sta[++top] = x;
    for (register int i = x; !isroot(i); i = fa[i]) Sta[++top] = fa[i];
    for (register int i = top; i; --i) Pushdown(Sta[i]);
    for (register int f; !isroot(x); Rotate(x)) {
      if (!isroot(f = fa[x])) {
        Rotate(getf(f) == getf(x) ? f : x);
      }
    }
  }
  inline void Access(int v) {
    for (register int t = 0; v; t = v, v = fa[v]) {
      Splay(v);
      ch[v][1] = t;
    }
  }
  inline void Mkroot(int x) {
    Access(x);
    Splay(x);
    Push(x);
  }
  inline int findrt(int x) {
    Access(x);
    Splay(x);
    while (ch[x][0]) x = ch[x][0];
    Splay(x);
    return x;
  }
  inline void Link(int u, int v) {
    Mkroot(u);
    fa[u] = v;
  }
  inline void Cut(int u, int v) {
    Mkroot(u);
    Access(v);
    Splay(v);
    ch[v][0] = fa[u] = 0;
  }
  inline bool issame(int u, int v) { return findrt(u) == findrt(v); }
} t1;
struct Segment_Tree {
  int Min[1000100], Sum[1000010], tag[1000010];
  inline pair<int, int> Merge(pair<int, int> p, pair<int, int> q) {
    if (p.first < q.first) return p;
    if (p.first > q.first) return q;
    return make_pair(p.first, p.second + q.second);
  }
  inline void Push(int now, int d) {
    Min[now] += d;
    tag[now] += d;
  }
  inline void Pushdown(int now, int l, int r) {
    if (tag[now])
      Push(now << 1, tag[now]), Push(now << 1 | 1, tag[now]), tag[now] = 0;
  }
  inline void Update(int now) {
    if (Min[now << 1] < Min[now << 1 | 1])
      Min[now] = Min[now << 1], Sum[now] = Sum[now << 1];
    else if (Min[now << 1] > Min[now << 1 | 1])
      Min[now] = Min[now << 1 | 1], Sum[now] = Sum[now << 1 | 1];
    else
      Min[now] = Min[now << 1], Sum[now] = Sum[now << 1] + Sum[now << 1 | 1];
  }
  inline void Build(int now, int l, int r) {
    if (l == r) {
      Sum[now] = 1;
      Min[now] = 0;
      return;
    }
    int mid = (l + r) >> 1;
    Build(now << 1, l, mid);
    Build(now << 1 | 1, mid + 1, r);
    Update(now);
  }
  inline void Modify(int now, int l, int r, int x, int y, int d) {
    if (x <= l && r <= y) {
      Push(now, d);
      return;
    }
    Pushdown(now, l, r);
    int mid = (l + r) >> 1;
    if (x <= mid) Modify(now << 1, l, mid, x, y, d);
    if (y > mid) Modify(now << 1 | 1, mid + 1, r, x, y, d);
    Update(now);
  }
  inline pair<int, int> Query(int now, int l, int r, int x, int y) {
    if (x <= l && r <= y) {
      return make_pair(Min[now], Sum[now]);
    }
    int mid = (l + r) >> 1;
    Pushdown(now, l, r);
    if (x > mid) return Query(now << 1 | 1, mid + 1, r, x, y);
    if (y <= mid) return Query(now << 1, l, mid, x, y);
    return Merge(Query(now << 1, l, mid, x, y),
                 Query(now << 1 | 1, mid + 1, r, x, y));
  }
} t2;
int n, m, N, L, R;
vector<int> f[200020];
pair<int, int> pos[200010];
inline void Gao2(pair<int, int> tmp1, pair<int, int> tmp2) {
  if (tmp2.first > n || tmp2.first < 1 || tmp2.second > m || tmp2.second < 1)
    return;
  int x = f[tmp1.first][tmp1.second], y = f[tmp2.first][tmp2.second];
  if (y < L) return;
  if (y >= R) return;
  t2.Modify(1, 1, N, 1, x, 1);
  t1.Cut(x, y);
}
inline void Erase(int x) {
  pair<int, int> tmp = pos[x];
  Gao2(tmp, make_pair(tmp.first + 1, tmp.second));
  Gao2(tmp, make_pair(tmp.first - 1, tmp.second));
  Gao2(tmp, make_pair(tmp.first, tmp.second + 1));
  Gao2(tmp, make_pair(tmp.first, tmp.second - 1));
}
inline void Gao(pair<int, int> tmp1, pair<int, int> tmp2) {
  if (tmp2.first > n || tmp2.first < 1 || tmp2.second > m || tmp2.second < 1)
    return;
  int x = f[tmp1.first][tmp1.second], y = f[tmp2.first][tmp2.second];
  if (y < L) return;
  if (y > R) return;
  int r1 = t1.findrt(x), r2 = t1.findrt(y);
  while (r1 == r2) {
    Erase(L);
    ++L;
    r1 = t1.findrt(x), r2 = t1.findrt(y);
    if (y < L) return;
  }
  if (y < L) return;
  t1.Link(x, y);
  t2.Modify(1, 1, N, 1, y, -1);
}
int main() {
  n = read(), m = read();
  N = n * m;
  for (register int i = 1; i <= n; ++i) {
    f[i].push_back(0);
    for (register int j = 1; j <= m; ++j) {
      int x = read();
      f[i].push_back(x);
      pos[x] = make_pair(i, j);
    }
  }
  L = 1;
  long long res = 0;
  t2.Build(1, 1, N);
  for (R = 1; R <= N; ++R) {
    t2.Modify(1, 1, N, 1, R, 1);
    pair<int, int> tmp = pos[R];
    Gao(tmp, make_pair(tmp.first + 1, tmp.second));
    Gao(tmp, make_pair(tmp.first - 1, tmp.second));
    Gao(tmp, make_pair(tmp.first, tmp.second + 1));
    Gao(tmp, make_pair(tmp.first, tmp.second - 1));
    pair<int, int> ans = t2.Query(1, 1, N, L, R);
    if (ans.first == 1) res += ans.second;
  }
  cout << res;
  return 0;
}
