#include <bits/stdc++.h>
const int maxn = 200000, maxm = 2000, MAX = 1e6 + 5, mod = 998244353;
const long double Pi = 3.14159265358979323846l, Eps = 1e-4;
template <class T>
inline bool equal(T x, T y) {
  return fabs(x - y) < Eps;
}
inline int add(int x, int y) {
  x += y;
  return x >= mod ? x - mod : x;
};
inline void inc(int &x, int y) {
  x += y;
  x -= (x >= mod ? mod : 0);
}
inline int mul(int x, int y) { return 1ll * x * y % mod; }
inline int Power(int x, int y, int Mod = mod) {
  int ans = 1;
  while (y) {
    if (y & 1) ans = (long long)ans * x % Mod;
    x = (long long)x * x % Mod, y >>= 1;
  }
  return ans;
}
template <class T>
inline T input() {
  T x;
  char ch;
  bool flag = false;
  while (!isdigit(ch = getchar())) flag |= ch == '-';
  for (x = ch ^ 48; isdigit(ch = getchar()); x = x * 10 + (ch ^ 48))
    ;
  return flag ? -x : x;
}
template <class T>
inline bool chkmin(T &x, T y) {
  x = x < y ? x : y;
  return x == y;
}
template <class T>
inline bool chkmax(T &x, T y) {
  x = x > y ? x : y;
  return x == y;
}
template <class T>
inline T gcd(T x, T y) {
  return !y ? x : gcd(y, x % y);
}
template <class T>
inline T sqrm(T x) {
  return (long long)x * x % mod;
}
template <class T>
inline T sqr(T x) {
  return x * x;
}
struct {
  inline operator int() { return input<int>(); }
  inline operator long long() { return input<long long>(); }
  template <class T>
  inline void operator()(T &x) {
    x = *this;
  }
  template <class T, class... A>
  inline void operator()(T &x, A &...a) {
    x = *this;
    this->operator()(a...);
  }
} read;
int n, m, tot;
int Map[maxm + 5][maxm + 5];
int x[maxn + 5], y[maxn + 5];
int dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0};
bool used[maxn + 5], vis[maxn + 5];
namespace Tree {
int min[maxn * 3], cnt[maxn * 3], add[maxn * 3];
void update(int rt) {
  if (min[rt << 1] < min[rt << 1 | 1])
    min[rt] = min[rt << 1], cnt[rt] = cnt[rt << 1];
  else if (min[rt << 1] > min[rt << 1 | 1])
    min[rt] = min[rt << 1 | 1], cnt[rt] = cnt[rt << 1 | 1];
  else
    min[rt] = min[rt << 1], cnt[rt] = cnt[rt << 1] + cnt[rt << 1 | 1];
}
void build(int rt, int l, int r) {
  if (l == r) return min[rt] = l, cnt[rt] = 1, void();
  build(rt << 1, l, ((l + r) >> 1)), build(rt << 1 | 1, ((l + r) >> 1) + 1, r);
  update(rt);
}
void Add(int rt, int v) { min[rt] += v, add[rt] += v; }
void pushdown(int rt) {
  if (!add[rt]) return void();
  Add(rt << 1, add[rt]);
  Add(rt << 1 | 1, add[rt]);
  add[rt] = 0;
}
void Add(int rt, int l, int r, int L, int R, int v) {
  if (L <= l && r <= R) return Add(rt, v);
  pushdown(rt);
  if (L <= ((l + r) >> 1)) Add(rt << 1, l, ((l + r) >> 1), L, R, v);
  if (R > ((l + r) >> 1)) Add(rt << 1 | 1, ((l + r) >> 1) + 1, r, L, R, v);
  update(rt);
}
void Add(int l, int r, int v) { return Add(1, 1, tot, l, r, v); }
void query(int rt, int l, int r, int L, int R, int &Min, int &res) {
  if (L <= l && r <= R) {
    if (min[rt] < Min)
      Min = min[rt], res = cnt[rt];
    else if (min[rt] == Min)
      res += cnt[rt];
    return void();
  }
  pushdown(rt);
  if (L <= ((l + r) >> 1)) query(rt << 1, l, ((l + r) >> 1), L, R, Min, res);
  if (R > ((l + r) >> 1))
    query(rt << 1 | 1, ((l + r) >> 1) + 1, r, L, R, Min, res);
}
int query(int l, int r) {
  int min = 0x3f3f3f3f, res = 0;
  query(1, 1, tot, l, r, min, res);
  return res;
}
}  // namespace Tree
namespace LCT {
int fa[maxn + 5], ch[maxn + 5][2];
bool rev[maxn + 5];
inline int pd(int x) { return ch[fa[x]][1] == x; }
inline bool isroot(int x) { return ch[fa[x]][0] != x && ch[fa[x]][1] != x; }
inline void reverse(int x) { std::swap(ch[x][0], ch[x][1]), rev[x] ^= 1; }
inline void rotate(int x) {
  int y = fa[x], g = fa[y], c = pd(x), B = ch[x][!c];
  if (!isroot(y)) ch[g][pd(y)] = x;
  ch[x][!c] = y, ch[y][c] = B;
  fa[x] = g, fa[y] = x;
  if (B) fa[B] = y;
}
void pushdown(int x) {
  if (!rev[x]) return void();
  if (ch[x][0]) reverse(ch[x][0]);
  if (ch[x][1]) reverse(ch[x][1]);
  rev[x] = 0;
}
void pushall(int x) {
  if (!isroot(x)) pushall(fa[x]);
  pushdown(x);
}
inline void splay(int x) {
  pushall(x);
  while (!isroot(x)) {
    int y = fa[x];
    if (!isroot(y)) rotate(pd(x) ^ pd(y) ? x : y);
    rotate(x);
  }
}
void access(int x) {
  for (int y = 0; x; x = fa[y = x]) splay(x), ch[x][1] = y;
}
int findroot(int x) {
  access(x), splay(x);
  while (ch[x][0]) pushdown(x), x = ch[x][0];
  return splay(x), x;
}
void makeroot(int x) { access(x), splay(x), reverse(x); }
void link(int x, int y) { makeroot(x), fa[x] = y; }
void cut(int x, int y) {
  makeroot(x), access(y), splay(y);
  ch[y][0] = fa[x] = 0;
}
}  // namespace LCT
bool check(int r) {
  for (int i = 0; i < 4; ++i) {
    int va = Map[x[r] + dx[i]][y[r] + dy[i]];
    if (used[va] || va > r) continue;
    for (int j = i + 1; j < 4; ++j) {
      int vb = Map[x[r] + dx[j]][y[r] + dy[j]];
      if (used[vb] || vb > r) continue;
      if (LCT::findroot(va) == LCT::findroot(vb)) return false;
    }
  }
  return true;
}
void add(int r) {
  vis[r] = true;
  for (int i = 0; i < 4; ++i) {
    int tox = x[r] + dx[i], toy = y[r] + dy[i], to = Map[tox][toy];
    if (!used[to] && to < r) {
      Tree::Add(r, tot, -1);
      LCT::link(r, to);
    }
  }
}
void del(int l) {
  Tree::Add(l, tot, -1), used[l] = true;
  for (int i = 0; i < 4; ++i) {
    int tox = x[l] + dx[i], toy = y[l] + dy[i], to = Map[tox][toy];
    if (vis[to] && to > l) {
      Tree::Add(to, tot, 1);
      LCT::cut(l, to);
    }
  }
}
signed main() {
  used[0] = true;
  read(n, m), tot = n * m;
  Tree::build(1, 1, tot);
  for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= m; ++j) {
      read(Map[i][j]);
      x[Map[i][j]] = i;
      y[Map[i][j]] = j;
    }
  long long ans = 0;
  for (int l = 1, r = 0; l <= tot; ++l) {
    while (r < tot && check(r + 1)) add(++r);
    ans += Tree::query(l, r);
    del(l);
  }
  printf("%lld\n", ans);
  return 0;
}
