#include <bits/stdc++.h>
using namespace std;
pair<int, int> merge(pair<int, int> x, pair<int, int> y) {
  if (x > y) swap(x, y);
  return (x.first != y.first) ? x
                              : pair<int, int>(x.first, x.second + y.second);
}
namespace LCT {
int fa[200005], ch[200005][2];
bool rev[200005];
inline bool isroot(int o) { return (ch[fa[o]][0] != o) && (ch[fa[o]][1] != o); }
inline void pushdown(int o) {
  if (rev[o]) {
    rev[ch[o][0]] ^= 1;
    rev[ch[o][1]] ^= 1;
    swap(ch[o][0], ch[o][1]);
    rev[o] = 0;
  }
}
void rotate(int x) {
  int y = fa[x], z = fa[y], d = (ch[y][1] == x);
  if (!isroot(y)) {
    if (ch[z][0] == y)
      ch[z][0] = x;
    else
      ch[z][1] = x;
  }
  fa[x] = z;
  fa[y] = x;
  fa[ch[x][d ^ 1]] = y;
  ch[y][d] = ch[x][d ^ 1];
  ch[x][d ^ 1] = y;
}
int st[200005], top;
void splay(int x) {
  st[++top] = x;
  for (int i = x; !isroot(i); i = fa[i]) st[++top] = fa[i];
  for (; top; top--) pushdown(st[top]);
  while (!isroot(x)) {
    int y = fa[x], z = fa[y];
    if (!isroot(y)) {
      if ((ch[y][0] == x) ^ (ch[z][0] == y))
        rotate(x);
      else
        rotate(y);
    }
    rotate(x);
  }
}
void access(int x) {
  int y = 0;
  while (x) {
    splay(x);
    ch[x][1] = y;
    y = x;
    x = fa[x];
  }
}
void beroot(int x) {
  access(x);
  splay(x);
  rev[x] ^= 1;
}
void link(int x, int y) {
  beroot(x);
  splay(x);
  fa[x] = y;
}
void cut(int x, int y) {
  beroot(x);
  access(y);
  splay(y);
  if (ch[y][0] != x || ch[x][0] || ch[x][1]) return;
  ch[y][0] = fa[x] = 0;
}
int findroot(int x) {
  access(x);
  splay(x);
  while (ch[x][0]) x = ch[x][0];
  splay(x);
  return x;
}
}  // namespace LCT
namespace SGT {
pair<int, int> minn[800000];
int addv[800000];
inline void pushdown(int o) {
  if (addv[o]) {
    minn[o * 2].first += addv[o];
    addv[o * 2] += addv[o];
    minn[o * 2 + 1].first += addv[o];
    addv[o * 2 + 1] += addv[o];
    addv[o] = 0;
  }
}
inline void pushup(int o) { minn[o] = merge(minn[o * 2], minn[o * 2 + 1]); }
void build(int l, int r, int o) {
  if (l == r)
    minn[o] = pair<int, int>(0, 1);
  else {
    int m = ((l + r) >> 1);
    build(l, m, o * 2);
    build(m + 1, r, o * 2 + 1);
    pushup(o);
  }
}
void update(int l, int r, int o, int lx, int rx, int p) {
  if (l >= lx && r <= rx) {
    minn[o].first += p;
    addv[o] += p;
  } else {
    pushdown(o);
    int m = ((l + r) >> 1);
    if (m >= lx) update(l, m, o * 2, lx, rx, p);
    if (m < rx) update(m + 1, r, o * 2 + 1, lx, rx, p);
    pushup(o);
  }
}
pair<int, int> query(int l, int r, int o, int lx, int rx) {
  if (l >= lx && r <= rx)
    return minn[o];
  else {
    pushdown(o);
    int m = ((l + r) >> 1);
    if (m >= rx) return query(l, m, o * 2, lx, rx);
    if (m < lx) return query(m + 1, r, o * 2 + 1, lx, rx);
    return merge(query(l, m, o * 2, lx, rx),
                 query(m + 1, r, o * 2 + 1, lx, rx));
  }
}
}  // namespace SGT
const int way[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int num[1005][1005];
pair<int, int> pos[200005];
bool in[200005];
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++) {
      scanf("%d", &num[i][j]);
      pos[num[i][j]] = pair<int, int>(i, j);
    }
  SGT::build(1, n * m, 1);
  long long ans = 0;
  int lx = 1;
  for (int i = 1; i <= n * m; i++) {
    in[i] = 1;
    int cur = 0;
    SGT::update(1, n * m, 1, 1, i, 1);
    while (cur < 4) {
      int x = num[pos[i].first + way[cur][0]][pos[i].second + way[cur][1]];
      while (in[x] && LCT::findroot(i) == LCT::findroot(x)) {
        in[lx] = 0;
        for (int j = 0; j < 4; j++) {
          int y = num[pos[lx].first + way[j][0]][pos[lx].second + way[j][1]];
          if (in[y] && LCT::findroot(lx) == LCT::findroot(y)) LCT::cut(lx, y);
        }
        lx++;
      }
      if (in[x]) {
        LCT::link(i, x);
        SGT::update(1, n * m, 1, 1, x, -1);
      }
      cur++;
    }
    ans += SGT::query(1, n * m, 1, lx, i).second;
  }
  printf("%lld\n", ans);
  return 0;
}
