#include <bits/stdc++.h>
using namespace std;
inline char gc() {
  static char now[1 << 16], *S, *T;
  if (T == S) {
    T = (S = now) + fread(now, 1, 1 << 16, stdin);
    if (T == S) return EOF;
  }
  return *S++;
}
inline long long read() {
  register long long x = 0, f = 1;
  char ch = gc();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = gc();
  }
  while (isdigit(ch)) {
    x = (x << 3) + (x << 1) + ch - '0';
    ch = gc();
  }
  return (f == 1) ? x : -x;
}
int n, m, a[303030], pre[302020][2];
const int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
inline int id(int x, int y) { return (x - 1) * m + y; }
struct LCT {
  struct node {
    int son[2], fa;
    bool tag;
  } g[303030];
  inline void reverse(int rt) {
    g[rt].tag ^= 1;
    swap(g[rt].son[0], g[rt].son[1]);
  }
  inline void pushdown(int rt) {
    if (g[rt].tag) {
      if (g[rt].son[0]) reverse(g[rt].son[0]);
      if (g[rt].son[1]) reverse(g[rt].son[1]);
      g[rt].tag = 0;
    }
  }
  inline bool wtson(int rt) { return (g[g[rt].fa].son[0] == rt ? 0 : 1); }
  inline bool isrt(int rt) {
    return (g[g[rt].fa].son[0] != rt && g[g[rt].fa].son[1] != rt);
  }
  inline void rotate(int rt) {
    int fa = g[rt].fa, fafa = g[fa].fa, wht = wtson(rt),
        son = g[rt].son[wht ^ 1], whtfa = wtson(fa);
    g[rt].fa = fafa;
    if (fafa && !isrt(fa)) g[fafa].son[whtfa] = rt;
    g[rt].son[wht ^ 1] = fa, g[fa].fa = rt;
    g[fa].son[wht] = son, g[son].fa = fa;
  }
  int sta[303030], top;
  inline void splay(int rt) {
    sta[top = 1] = rt;
    for (int i = rt; !isrt(i); i = g[i].fa) sta[++top] = g[i].fa;
    for (; top; top--) pushdown(sta[top]);
    while (!isrt(rt)) {
      int fa = g[rt].fa;
      if (isrt(fa))
        rotate(rt);
      else if (wtson(rt) == wtson(fa)) {
        rotate(fa), rotate(rt);
      } else {
        rotate(rt), rotate(rt);
      }
    }
  }
  inline void access(int rt) {
    for (int x = rt, y = 0; x; x = g[y = x].fa) {
      splay(x), g[x].son[1] = y;
    }
  }
  inline void makert(int rt) { access(rt), splay(rt), reverse(rt); }
  inline int findrt(int rt) {
    access(rt), splay(rt);
    while (g[rt].son[0]) pushdown(rt), rt = g[rt].son[0];
    int ans = rt;
    splay(rt);
    return ans;
  }
  inline void link(int x, int y) {
    makert(y);
    if (findrt(x) != y) g[y].fa = x;
  }
  inline void cut(int x, int y) {
    makert(y), access(x), splay(x);
    if (g[y].fa == x && !g[y].son[1]) {
      g[y].fa = g[x].son[0] = 0;
    }
  }
  inline bool query(int x, int y) { return (findrt(x) == findrt(y)); }
} T;
bool vis[303030];
int seg[1202020], cnt[1202020], ncir[303030], tag[1202020];
inline void pushup(int rt) {
  if (seg[rt << 1] == seg[rt << 1 | 1])
    cnt[rt] = cnt[rt << 1] + cnt[rt << 1 | 1];
  else if (seg[rt << 1] < seg[rt << 1 | 1])
    cnt[rt] = cnt[rt << 1];
  else
    cnt[rt] = cnt[rt << 1 | 1];
  seg[rt] = min(seg[rt << 1], seg[rt << 1 | 1]);
}
inline void pushdown(int rt) {
  if (tag[rt]) {
    seg[rt << 1] += tag[rt];
    tag[rt << 1] += tag[rt];
    seg[rt << 1 | 1] += tag[rt];
    tag[rt << 1 | 1] += tag[rt];
    tag[rt] = 0;
  }
}
void build(int rt, int lb, int rb) {
  if (lb == rb) return (void)(cnt[rt] = 1);
  build(rt << 1, lb, ((lb + rb) >> 1));
  build(rt << 1 | 1, ((lb + rb) >> 1) + 1, rb);
  pushup(rt);
}
void update(int rt, int lb, int rb, int l, int r, int w) {
  if (lb > r || rb < l) return;
  if (lb >= l && rb <= r) return (void)(seg[rt] += w, tag[rt] += w);
  pushdown(rt);
  update(rt << 1, lb, ((lb + rb) >> 1), l, r, w),
      update(rt << 1 | 1, ((lb + rb) >> 1) + 1, rb, l, r, w);
  pushup(rt);
}
int query(int rt, int lb, int rb, int l, int r) {
  if (lb > r || rb < l) return 0;
  if (lb >= l && rb <= r) return (seg[rt] == 1 ? cnt[rt] : 0);
  pushdown(rt);
  return query(rt << 1, lb, ((lb + rb) >> 1), l, r) +
         query(rt << 1 | 1, ((lb + rb) >> 1) + 1, rb, l, r);
}
signed main() {
  n = read(), m = read();
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      int x = read();
      a[id(i, j)] = x;
      pre[x][0] = i, pre[x][1] = j;
    }
  }
  ncir[1] = vis[id(pre[1][0], pre[1][1])] = 1;
  int i, j, x, y, xx, yy, X, Y, XX, YY, K, k;
  for (i = 2, j = 1; i <= n * m; i++) {
    vis[id(pre[i][0], pre[i][1])] = 1;
    for (k = 0; k < 4; k++) {
      x = pre[i][0], y = pre[i][1], xx = x + dx[k], yy = y + dy[k];
      if (xx < 1 || yy < 1 || xx > n || yy > m || !vis[id(xx, yy)]) continue;
      while (T.query(id(xx, yy), id(x, y))) {
        vis[id(pre[j][0], pre[j][1])] = 0;
        for (K = 0; K < 4; K++) {
          X = pre[j][0], Y = pre[j][1], XX = X + dx[K], YY = Y + dy[K];
          if (XX < 1 || YY < 1 || XX > n || YY > m || !vis[id(XX, YY)])
            continue;
          T.cut(id(XX, YY), id(X, Y));
        }
        j++;
      }
      T.link(id(xx, yy), id(x, y));
    }
    ncir[i] = j;
  }
  long long ans = 0;
  build(1, 1, n * m);
  for (int i = 1; i <= n * m; i++) {
    update(1, 1, n * m, 1, i, 1);
    for (k = 0; k < 4; k++) {
      x = pre[i][0], y = pre[i][1], xx = x + dx[k], yy = y + dy[k];
      if (xx < 1 || yy < 1 || xx > n || yy > m) continue;
      if (a[id(xx, yy)] < i) {
        update(1, 1, n * m, 1, a[id(xx, yy)], -1);
      }
    }
    ans += query(1, 1, n * m, ncir[i], i);
  }
  cout << ans;
  return 0;
}
