#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int dx[] = {0, 0, -1, 1};
const int dy[] = {1, -1, 0, 0};
int add(int x, int y) {
  x += y;
  if (x >= 998244353) x -= 998244353;
  return x;
}
int ch[N][2], fa[N], rev[N];
int isroot(int x) { return ch[fa[x]][0] != x && ch[fa[x]][1] != x; }
int get(int x) { return ch[fa[x]][1] == x; }
void pushup(int x) {}
void Rev(int x) {
  swap(ch[x][0], ch[x][1]);
  rev[x] ^= 1;
}
void pushdown(int x) {
  if (x && rev[x]) {
    if (ch[x][0]) Rev(ch[x][0]);
    if (ch[x][1]) Rev(ch[x][1]);
    rev[x] = 0;
  }
}
void rotate(int x) {
  int old = fa[x], oldf = fa[old];
  if (!isroot(old)) {
    ch[oldf][get(old)] = x;
  }
  fa[x] = oldf;
  int d = ch[old][1] == x;
  ch[old][d] = ch[x][d ^ 1];
  if (ch[x][d ^ 1]) fa[ch[x][d ^ 1]] = old;
  ch[x][d ^ 1] = old;
  fa[old] = x;
  pushup(old);
  pushup(x);
}
int stay[N];
void splay(int x) {
  int top = 0;
  stay[++top] = x;
  for (int i = x; !isroot(i); i = fa[i]) stay[++top] = fa[i];
  for (int i = top; i >= 1; i--) pushdown(stay[i]);
  for (int f = fa[x]; !isroot(x); rotate(x))
    if (!isroot(f = fa[x])) {
      rotate(get(f) == get(x) ? f : x);
    }
}
void access(int x) {
  for (int t = 0; x; t = x, x = fa[x]) {
    splay(x);
    ch[x][1] = t;
  }
}
void wroot(int x) {
  access(x);
  splay(x);
  Rev(x);
}
void link(int x, int y) {
  wroot(x);
  fa[x] = y;
}
void cut(int x, int y) {
  wroot(x);
  access(y);
  splay(y);
  ch[y][0] = fa[x] = 0;
}
int find(int x) {
  access(x);
  splay(x);
  while (ch[x][0]) {
    x = ch[x][0];
  }
  return x;
}
struct Node {
  int minm, cnt, tag;
} tr[N << 2];
void down(int x) {
  if (tr[x].tag != 0) {
    tr[x << 1].minm += tr[x].tag;
    tr[x << 1].tag += tr[x].tag;
    tr[x << 1 | 1].minm += tr[x].tag;
    tr[x << 1 | 1].tag += tr[x].tag;
    tr[x].tag = 0;
  }
}
void up(int x) {
  tr[x].minm = tr[x << 1].minm;
  tr[x].cnt = tr[x << 1].cnt;
  if (tr[x << 1 | 1].minm < tr[x].minm)
    tr[x].minm = tr[x << 1 | 1].minm, tr[x].cnt = tr[x << 1 | 1].cnt;
  else if (tr[x << 1 | 1].minm == tr[x].minm)
    tr[x].cnt += tr[x << 1 | 1].cnt;
}
void build(int x, int l, int r) {
  if (l == r) {
    tr[x].cnt = 1;
    return;
  }
  int mid = l + r >> 1;
  build(x << 1, l, mid);
  build(x << 1 | 1, mid + 1, r);
  up(x);
  return;
}
void modify(int x, int l, int r, int ql, int qr, int v) {
  if (ql <= l && r <= qr) {
    tr[x].minm += v;
    tr[x].tag += v;
    return;
  }
  int mid = l + r >> 1;
  down(x);
  if (ql <= mid) modify(x << 1, l, mid, ql, qr, v);
  if (mid < qr) modify(x << 1 | 1, mid + 1, r, ql, qr, v);
  up(x);
}
void Merge(pair<int, int> &x, pair<int, int> y) {
  if (x.first > y.first)
    x = y;
  else if (x.first == y.first)
    x.second += y.second;
}
pair<int, int> query(int x, int l, int r, int ql, int qr) {
  if (ql <= l && r <= qr) {
    return make_pair(tr[x].minm, tr[x].cnt);
  }
  int mid = l + r >> 1;
  pair<int, int> res = make_pair(998244353, 0);
  down(x);
  if (ql <= mid) Merge(res, query(x << 1, l, mid, ql, qr));
  if (mid < qr) Merge(res, query(x << 1 | 1, mid + 1, r, ql, qr));
  return res;
}
int n, m, mat[2010][2010];
long long res;
pair<int, int> pos[N];
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      scanf("%d", &mat[i][j]);
      pos[mat[i][j]] = make_pair(i, j);
    }
  }
  build(1, 1, n * m);
  int p = 1;
  for (int i = 1; i <= n * m; i++) {
    int x = pos[i].first, y = pos[i].second;
    while (1) {
      bool flag = 1;
      for (int j = 0; j < 4; j++) {
        int nx = x + dx[j], ny = y + dy[j];
        if (nx < 1 || nx > n || ny < 1 || ny > m || mat[nx][ny] > i ||
            mat[nx][ny] < p)
          continue;
        for (int d = j + 1; d < 4; d++) {
          int nnx = x + dx[d], nny = y + dy[d];
          if (nnx < 1 || nnx > n || nny < 1 || nny > m || mat[nnx][nny] > i ||
              mat[nnx][nny] < p)
            continue;
          if (find(mat[nx][ny]) == find(mat[nnx][nny])) {
            flag = 0;
          }
        }
      }
      if (flag) break;
      int x = pos[p].first, y = pos[p].second;
      for (int d = 0; d < 4; d++) {
        int nx = x + dx[d], ny = y + dy[d];
        if (nx < 1 || nx > n || ny < 1 || ny > m || mat[nx][ny] > i ||
            mat[nx][ny] < p)
          continue;
        cut(p, mat[nx][ny]);
      }
      p++;
    }
    modify(1, 1, n * m, 1, i, 1);
    for (int j = 0; j < 4; j++) {
      int nx = x + dx[j], ny = y + dy[j];
      if (nx < 1 || nx > n || ny < 1 || ny > m || mat[nx][ny] > i) continue;
      modify(1, 1, n * m, 1, mat[nx][ny], -1);
    }
    for (int j = 0; j < 4; j++) {
      int nx = x + dx[j], ny = y + dy[j];
      if (nx < 1 || nx > n || ny < 1 || ny > m || mat[nx][ny] > i ||
          mat[nx][ny] < p)
        continue;
      link(mat[nx][ny], i);
    }
    pair<int, int> ret = query(1, 1, n * m, p, i);
    res += ret.second;
  }
  cout << res << endl;
  return 0;
}
