#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline T rd() {
  T nmb = 0;
  int sgn = 0;
  char chr = getchar();
  while (!isdigit(chr)) {
    if (chr == '-') sgn = 1;
    chr = getchar();
  }
  while (isdigit(chr)) {
    nmb = (nmb << 3) + (nmb << 1) + chr - '0';
    chr = getchar();
  }
  return sgn ? -nmb : nmb;
}
template <typename T>
void wt(T nmb) {
  if (nmb > 9) wt(nmb / 10);
  putchar(nmb % 10 + '0');
}
template <typename T>
inline void cmax(T &x, T y) {
  x = x > y ? x : y;
}
template <typename T>
inline void cmin(T &x, T y) {
  x = x < y ? x : y;
}
inline void proc_status() {
  ifstream t("/proc/self/status");
  cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>())
       << endl;
}
const int N = 2e5 + 10;
const int inf = 2e9;
namespace LCT {
int val[N];
int fa[N], ch[N][2];
int st[N], top;
int tag[N];
inline int notroot(int x) { return x == ch[fa[x]][0] || x == ch[fa[x]][1]; }
inline int pos(int x) { return x == ch[fa[x]][1]; }
inline void con(int f, int x, int t) { fa[x] = f, ch[f][t] = x; }
inline void pushdown(int x) {
  if (!tag[x]) return;
  swap(ch[x][0], ch[x][1]);
  tag[ch[x][0]] ^= 1, tag[ch[x][1]] ^= 1;
  tag[x] = 0;
}
inline void rotate(int x) {
  int y = fa[x], f = fa[y];
  int xt = pos(x), yt = pos(y);
  if (notroot(y))
    con(f, x, yt);
  else
    fa[x] = f;
  con(y, ch[x][xt ^ 1], xt);
  con(x, y, xt ^ 1);
}
inline void splay(int x) {
  top = 0;
  while (notroot(x)) st[++top] = x, x = fa[x];
  st[++top] = x;
  for (int i = top; i; --i) pushdown(st[i]);
  x = st[1];
  while (notroot(x)) {
    if (!notroot(fa[x]))
      rotate(x);
    else if (pos(x) == pos(fa[x]))
      rotate(fa[x]), rotate(x);
    else
      rotate(x), rotate(x);
  }
}
inline void access(int x) {
  for (int lst = 0; x; lst = x, x = fa[x]) splay(x), ch[x][1] = lst;
}
inline void toroot(int x) {
  access(x), splay(x);
  tag[x] ^= 1;
}
inline int findroot(int x) {
  access(x), splay(x);
  while (ch[x][0]) x = ch[x][0];
  splay(x);
  return x;
}
inline void link(int x, int y) {
  toroot(x);
  if (findroot(y) == x) return;
  fa[x] = y;
}
inline void cut(int x, int y) {
  toroot(x);
  if (findroot(y) != x) return;
  if (fa[y] == x && !ch[x][0]) ch[x][1] = fa[y] = 0;
}
}  // namespace LCT
using namespace LCT;
namespace SGT {
int mn[N << 2], num[N << 2], tag[N << 2];
inline void build(int r, int x, int y) {
  num[r] = y - x + 1;
  if (x == y) return;
  int m = (x + y) >> 1;
  build(r << 1, x, m), build(r << 1 | 1, m + 1, y);
}
inline void pushup(int r) {
  mn[r] = min(mn[r << 1], mn[r << 1 | 1]);
  if (mn[r << 1] == mn[r << 1 | 1])
    num[r] = num[r << 1] + num[r << 1 | 1];
  else if (mn[r << 1] < mn[r << 1 | 1])
    num[r] = num[r << 1];
  else
    num[r] = num[r << 1 | 1];
}
inline void pushdown(int r) {
  if (!tag[r]) return;
  mn[r << 1] += tag[r], mn[r << 1 | 1] += tag[r];
  tag[r << 1] += tag[r], tag[r << 1 | 1] += tag[r];
  tag[r] = 0;
}
void add(int r, int x, int y, int u, int v, int p) {
  if (u <= x && y <= v) {
    mn[r] += p;
    tag[r] += p;
    return;
  }
  pushdown(r);
  int m = (x + y) >> 1;
  if (u <= m) add(r << 1, x, m, u, v, p);
  if (m < v) add(r << 1 | 1, m + 1, y, u, v, p);
  pushup(r);
}
pair<int, int> query(int r, int x, int y, int u, int v) {
  if (u <= x && y <= v) return make_pair(mn[r], num[r]);
  pushdown(r);
  int m = (x + y) >> 1;
  pair<int, int> res = make_pair(inf, 0);
  if (u <= m) res = query(r << 1, x, m, u, v);
  if (m < v) {
    pair<int, int> rec = query(r << 1 | 1, m + 1, y, u, v);
    if (res.first == rec.first)
      res.second = res.second + rec.second;
    else if (res.first > rec.first)
      res.second = rec.second;
    res.first = min(res.first, rec.first);
  }
  return res;
}
}  // namespace SGT
using namespace SGT;
int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
int n, m, lim;
int a[N];
pair<int, int> Pos[N];
int col[N];
inline int get(int x, int y) { return (x - 1) * m + y; }
inline int Out(int x, int y) {
  if (x < 1 || x > n || y < 1 || y > m) return 1;
  return 0;
}
inline void Link(pair<int, int> t) {
  for (int p = 0; p < 4; ++p) {
    int u = t.first + dir[p][0], v = t.second + dir[p][1];
    if (Out(u, v)) continue;
    if (col[get(u, v)]) link(get(t.first, t.second), get(u, v));
  }
  col[get(t.first, t.second)] = 1;
}
inline void Cut(pair<int, int> t) {
  for (int p = 0; p < 4; ++p) {
    int u = t.first + dir[p][0], v = t.second + dir[p][1];
    if (Out(u, v)) continue;
    if (col[get(u, v)]) cut(get(t.first, t.second), get(u, v));
  }
  col[get(t.first, t.second)] = 0;
}
int Rec[4];
inline int Linked(pair<int, int> t) {
  for (int i = 0; i < 4; ++i) Rec[i] = 0;
  for (int p = 0; p < 4; ++p) {
    int u = t.first + dir[p][0], v = t.second + dir[p][1];
    if (Out(u, v)) continue;
    Rec[p] = findroot(get(u, v));
  }
  for (int i = 0; i < 4; ++i)
    for (int j = i + 1; j < 4; ++j)
      if (Rec[i] && Rec[j] && Rec[i] == Rec[j]) return 1;
  return 0;
}
int main() {
  n = rd<int>(), m = rd<int>();
  lim = n * m;
  for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= m; ++j) {
      int k = rd<int>();
      a[get(i, j)] = k;
      Pos[k] = make_pair(i, j);
    }
  col[get(Pos[1].first, Pos[1].second)] = 1;
  build(1, 1, lim);
  add(1, 1, lim, 1, 1, 1);
  long long Ans = 1;
  for (int i = 2, k = 1; i <= lim; ++i) {
    while (Linked(Pos[i])) Cut(Pos[k]), ++k;
    Link(Pos[i]);
    add(1, 1, lim, 1, i, 1);
    for (int p = 0; p < 4; ++p) {
      int u = Pos[i].first + dir[p][0], v = Pos[i].second + dir[p][1];
      if (Out(u, v)) continue;
      if (a[get(u, v)] < i) add(1, 1, lim, 1, a[get(u, v)], -1);
    }
    pair<int, int> res = query(1, 1, lim, k, i);
    if (res.first == 1) Ans += res.second;
  }
  printf("%lld\n", Ans);
  return 0;
}
