#include <bits/stdc++.h>
#pragma GCC optimize(3)
using namespace std;
template <typename T>
inline bool chkmin(T &x, T y) {
  return x > y ? x = y, 1 : 0;
}
template <typename T>
inline bool chkmax(T &x, T y) {
  return x < y ? x = y, 1 : 0;
}
template <typename T>
inline void read(T &x) {
  char ch = getchar();
  int f = 1;
  x = 0;
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
  x *= f;
}
template <typename T, typename... Args>
inline void read(T &x, Args &...args) {
  read(x), read(args...);
}
int n, m, a[1050][1050], st;
long long ans;
pair<int, int> pos[200050];
struct LCT {
  int fa[200050], ch[200050][2], tag[200050];
  bool nroot(int u) { return ch[fa[u]][0] == u || ch[fa[u]][1] == u; }
  bool son(int u) { return ch[fa[u]][1] == u; }
  void rotate(int x) {
    int y = fa[x], z = fa[y], k = son(x), w = ch[x][!k];
    if (nroot(y)) ch[z][son(y)] = x;
    ch[x][!k] = y, ch[y][k] = w;
    fa[w] = y, fa[y] = x, fa[x] = z;
  }
  void put_tag(int u) { tag[u] ^= 1, swap(ch[u][0], ch[u][1]); }
  void push(int u) {
    if (tag[u]) put_tag(ch[u][0]), put_tag(ch[u][1]), tag[u] = 0;
  }
  void pushall(int u) {
    if (nroot(u)) pushall(fa[u]);
    push(u);
  }
  void splay(int x) {
    pushall(x);
    while (nroot(x)) {
      int y = fa[x];
      if (nroot(y)) rotate(son(y) ^ son(x) ? x : y);
      rotate(x);
    }
  }
  void access(int x) {
    for (register int y = 0; x; x = fa[y = x]) splay(x), ch[x][1] = y;
  }
  void mroot(int u) { access(u), splay(u), put_tag(u); }
  void split(int u, int v) { mroot(u), access(v), splay(v); }
  void link(int u, int v) { split(u, v), fa[u] = v; }
  void cut(int u, int v) { split(u, v), ch[v][0] = fa[u] = 0; }
  int find(int u) {
    access(u), splay(u);
    while (ch[u][0]) push(u = ch[u][0]);
    return splay(u), u;
  }
} T;
struct node {
  int minv, cnt;
  node operator+(const int x) { return node{minv + x, cnt}; }
  node operator+(const node &x) {
    node r;
    r.minv = min(minv, x.minv);
    r.cnt = cnt * (minv == r.minv) + x.cnt * (x.minv == r.minv);
    return r;
  }
};
struct SGT {
  int tag[200050 << 2];
  node res[200050 << 2];
  void build(int u, int l, int r) {
    if (l == r) return (void)(res[u].cnt = 1);
    build(u << 1, l, ((l + r) >> 1)), build(u << 1 | 1, ((l + r) >> 1) + 1, r);
    res[u] = res[u << 1] + res[u << 1 | 1];
  }
  void put_tag(int u, int w) { tag[u] += w, res[u] = res[u] + w; }
  void push(int u) {
    if (tag[u])
      put_tag(u << 1, tag[u]), put_tag(u << 1 | 1, tag[u]), tag[u] = 0;
  }
  void modify(int u, int l, int r, int tl, int tr, int w) {
    if (tl <= l && r <= tr) return put_tag(u, w);
    push(u);
    if (tl <= ((l + r) >> 1)) modify(u << 1, l, ((l + r) >> 1), tl, tr, w);
    if (((l + r) >> 1) < tr)
      modify(u << 1 | 1, ((l + r) >> 1) + 1, r, tl, tr, w);
    res[u] = res[u << 1] + res[u << 1 | 1];
  }
  node query(int u, int l, int r, int tl, int tr) {
    if (tl <= l && r <= tr) return res[u];
    push(u);
    if (tr <= ((l + r) >> 1)) return query(u << 1, l, ((l + r) >> 1), tl, tr);
    if (((l + r) >> 1) < tl)
      return query(u << 1 | 1, ((l + r) >> 1) + 1, r, tl, tr);
    return query(u << 1, l, ((l + r) >> 1), tl, tr) +
           query(u << 1 | 1, ((l + r) >> 1) + 1, r, tl, tr);
  }
} S;
void insert(int u, int v) {
  if (v < st || v > u) return;
  while (T.find(u) == T.find(v)) {
    int x = pos[st].first, y = pos[st].second;
    if (st <= a[x + 1][y] && a[x + 1][y] < u) T.cut(st, a[x + 1][y]);
    if (st <= a[x - 1][y] && a[x - 1][y] < u) T.cut(st, a[x - 1][y]);
    if (st <= a[x][y + 1] && a[x][y + 1] < u) T.cut(st, a[x][y + 1]);
    if (st <= a[x][y - 1] && a[x][y - 1] < u) T.cut(st, a[x][y - 1]);
    ++st;
  }
  if (st <= v) T.link(u, v);
  S.modify(1, 1, n * m, 1, v, -1);
}
int main() {
  read(n, m);
  for (register int i = 1; i <= n; ++i)
    for (register int j = 1; j <= m; ++j)
      read(a[i][j]), pos[a[i][j]] = make_pair(i, j);
  S.build(1, 1, n * m);
  st = 1;
  for (register int i = 1; i <= n * m; ++i) {
    S.modify(1, 1, n * m, 1, i, 1);
    int x = pos[i].first, y = pos[i].second;
    insert(i, a[x - 1][y]), insert(i, a[x + 1][y]), insert(i, a[x][y - 1]),
        insert(i, a[x][y + 1]);
    node _r = S.query(1, 1, n * m, st, i);
    ans += _r.cnt;
  }
  cout << ans << endl;
  return 0;
}
